如何将值存储到泛型类字段(Mono.Cecil)

时间:2015-03-31 15:43:48

标签: c# generics il mono.cecil

我正在使用Mono.Cecil重写一些程序集。给定一个带有字符串字段的泛型类。我想在这个类的方法中生成代码,该类写入该字段。 这是实现这一目标的代码:

var origInstanceField = type.Fields.First(fld => fld.Name.Equals("_original"));
InsertBeforeReturn(instanceMethod.Body, new[]
{
   Instruction.Create(OpCodes.Ldarg_0),
   Instruction.Create(OpCodes.Ldstr, "genCodeToOriginal"),
   Instruction.Create(OpCodes.Stfld, origInstanceField)
});

对于非泛型类,它就像一个魅力。对于泛型类,它会产生错误的IL。如果您查看反编译的IL,您可以发现与编译器发出的相同指令相比的差异。

.method public hidebysig instance void FillFields() cil managed
{
.maxstack 8
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldstr "non-gen code to non-gen field"
L_0007: stfld string TestConsole.GenericClass`1<!T>::_original
L_0017: ldarg.0 
L_0018: ldstr "genCodeToOriginal"
L_001d: stfld string TestConsole.GenericClass`1::_original
L_0022: ret 
}

字段引用指向开放泛型类型[GenericClass&lt;&gt;],而不指向要构造的类型[GenericClass&lt; T&GT]。 我也尝试使用静态字段,结果相同。
任何想法如何才能找到正确的FieldDefinition?

1 个答案:

答案 0 :(得分:6)

通过查看Anotar(https://github.com/Fody/Anotar)的源代码,我设法找到了解决方案。诀窍是使用类型定义创建一个字段引用,引用实例化的泛型,而不是原始的泛型。

var declaringType = new GenericInstanceType(definition.DeclaringType);
foreach (var parameter in definition.DeclaringType.GenericParameters)
{
     declaringType.GenericArguments.Add(parameter);
}
return new FieldReference(definition.Name, definition.FieldType, declaringType);

对来自类型的FieldDefinition使用此转换可以得到正确的FieldReference。将泛型参数提供给泛型参数有点奇怪但有意义。