2017-10-15 145 views
0

尋找解決辦法,如何在實例構造函數中指定我在RT中動態創建的支持字段的屬性。簽名與編譯器生成的屬性匹配爲自動屬性。基本上它們將等同於下面列出的代碼。通過反射發射在構造函數中分配字段

使用.NET核2.0

問:我如何分配使用發射構造函數中的支持字段?

例如:

public class MyClass { 
    public MyClass(int f1, string f2) { 
    _field1 = f1; 
    _field2 = f2; 
    } 

    private readonly int _field1; 
    private readonly string _field2; 

    public int Field1 { get; } 
    public string Field2 { get; } 
} 

private static void CreateConstructor(TypeBuilder typeBuilder, IReadOnlyList<dynamic> backingFields) { 
    var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(KeyValuePair<string, string>), typeof(Dictionary<string, Type>)}); 
    var ctorIL = constructorBuilder.GetILGenerator(); 

    // Load the current instance ref in arg 0, along 
    // with the value of parameter "x" stored in arg X, into stfld. 

    for (var x = 0; x < backingFields.Count; x++) { 
    ctorIL.Emit(OpCodes.Ldarg_0); 
    ctorIL.Emit(OpCodes.Ldarg_S, x+1); 
    ctorIL.Emit(OpCodes.Stfld, backingFields[x]); 
    } 

    ctorIL.Emit(OpCodes.Ret); 
} 

public .cctor(KeyValuePair<string, string> kvp, Dictionary<string, Type> collection) { 
    _Name = kvp.Key; 
    _JSON = kvp.Value; 
    _PropertyInfo = collection; 
    } 

遍歷接口中定義的方法,並在新類型創建一個新的屬性&存取瓦特/私人設置器。

public interface IComplexType { 
    string Name { get; set; } 
    string JSON { get; set; } 
    object PropertyInfo { get; set; } 
    } 
+0

代碼DOM是顯著比Refection Emit更容易 – MickyD

+1

您發佈的代碼似乎將構造函數參數分配給後備字段。它不工作? –

+0

有些東西不能正常工作。它編譯並返回類型。能夠創建一個實例..檢查時,我缺少一些字段/屬性。例如,我應該有一個包含3個字段的Interface類。 JSON會將附加的字段/屬性/方法附加到工作的類中,但我試圖使界面中的成員只能讀取。 public interface IComplexType {Name} {get;組; } string JSON {get;組; } [Bindable(true)] [TypeConverter(typeof(StringConverter))] object PropertyInfo {get;組; } } – Latency

回答

1

已解決!

需要更改構造函數參數以匹配迭代次數,因爲它很難將Ldarg_1設置爲KeyValuePair並分別爲其分配Key & Value。

通過消除KVP並提供構造函數定義的附加參數如下:

var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(string), typeof(string), typeof(Dictionary<string, Type>)}); 
    var ctorIl = constructorBuilder.GetILGenerator(); 

    for (var x = 0; x < backingFields.Count; x++) { 
    ctorIl.Emit(OpCodes.Ldarg_0); 
    ctorIl.Emit(OpCodes.Ldarg_S, x + 1); 
    ctorIl.Emit(OpCodes.Stfld, backingFields[x]); 
    } 

    ctorIl.Emit(OpCodes.Ret); 

要調用,我只是提取KVP這裏的內容:

return (T) Activator.CreateInstance(TypeCollection[type], kvp.Key, kvp.Value, collection);