2015-03-31 60 views
6

我正在使用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 <>]和不將被構造類型[GenericClass < T>]。 我也嘗試過使用相同結果的靜態字段。
任何想法如何才能到達正確的FieldDefinition?

+0

爲什麼你不只是使用反射? – Servy 2015-03-31 15:47:12

+0

什麼是'type'?它不能是'TypeBuilder',因爲它沒有'Fields'屬性。 – svick 2015-03-31 17:14:06

+0

反射可以很好,但在我的情況下,我也會創建與塞西爾領域,所以沒有反思。變量類型是一個TypeDefinition。 – csnemes 2015-03-31 17:44:12

回答

4

我已經設法通過查看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。將泛型參數提供給泛型參數有點奇怪,但有道理。

+0

真的很有魅力! – 2017-01-09 14:05:58