我正在编写自己的序列化程序,它会发出IL来生成[de]序列化代码。
对于nullables,我认为我可以生成以下内容(以int?
为例)(假设我们已经生成[de]序列化int
的方法):
public static void Serialize(Stream stream, int? value, object context)
{
Serialize(stream, (int)value, context);
}
public static void Deseiralize(Stream stream, out int? value, object context)
{
int tmp;
Deserialize(stream, out tmp, context);
value = tmp;
}
这是我如何产生的:
public override void GenSerializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var serialize = GetSerializeCall(underlyingType);
// Serialize(stream, (UnderlyingType)value, context);
emit.ldarg_0()
.ldarg_1()
.unbox_any(underlyingType)
.ldarg_2()
.call(serialize)
.ret();
}
public override void GenDeserializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var deserialize = GetDeserializeCall(underlyingType);
// UnderlyingType tmp; Deserialize(stream, out tmp, context);
var tmp = emit.declocal(underlyingType);
emit.ldarg_0()
.ldloca_s(tmp)
.ldarg_2()
.call(deserialize);
// value = tmp;
emit.ldarg_1()
.ldloc_s(tmp)
.stind_ref()
.ret();
}
我还生成一个用于调试的程序集。我在ILSpy中加载它,C#代码看起来与我的想法完全一样。但peverify还有其他的话要说......
我想了一会儿,然后意识到Nullable<T>
是一个结构,所以我应该使用Ldarga
代替Ldarg
,所以我将ldarg_1()
更改为{ {1}}
现在peverify给出:
ldarga(1)
我认为它与[IL]: Error: [C:\Users\vexe\Desktop\MyExtensionsAndHelpers\Solution\CustomSerializer\bin\Release\SerTest.dll : FastSerializer::Serialize][offset 0x00000007][found address of value 'System.Nullable`1[System.Int32]'] Expected an ObjRef on the stack.
转化运算符有关,所以我尝试了Nullable<T>
属性:
Value
peverify很高兴这个!
问题是,为什么在将可为空的nullable转换为其基础类型时,从 var underlyingType = Nullable.GetUnderlyingType(type);
var serialize = GetSerializeCall(underlyingType);
var getValue = type.GetProperty("Value").GetGetMethod();
// Serialize(stream, value.get_Value(), context);
emit.ldarg_0()
.ldarga(1)
.call(getValue)
.ldarg_2()
.call(serialize)
.ret();
到T
的显式运算符没有启动?
此外,即使在执行Nullable<T>
时使用Ldarga
代替Ldarg
,我也无法摆脱反序列化中的错误 - 我想我可以尝试一下隐式转换正在做。即value = tmp;
,但我想知道我做错了什么。
注意:&#39;发出&#39;只是我用来生成IL的助手。它在内部使用value = new Nullable<int>(tmp);
并在每次操作后自行返回,因此我可以将调用链接在一起。
编辑:这里是最终的代码,包括笔记和所有内容。
ILGenerator
答案 0 :(得分:2)
显式和隐式转换纯粹是C#概念。
IL对可空类型没有任何特殊意识(将它们装入Object
s除外);您需要明确使用.Value
或致电ctor。
答案 1 :(得分:1)
运算符仅适用于C#和VB.NET编译器。 IL和IL几代人对此一无所知。