.NET(C#):反射Emit建立泛型方法(包括泛型參數約束)

來源:互聯網
上載者:User

反射Emit中的TypeBuilder.DefineMethod並沒有直接提供對泛型參數的支援。整體過程也不是一個簡單的方法調用就可以解決的,具體總結如下過程:

  1. 調用沒有指定參數和傳回值類型的TypeBuilder.DefineMethod重載,得到MethodBuilder。
  2. 使用MethodBuilder.DefineGenericParameters方法來定義泛型參數的類型名稱,比如T,K,V……然後最終方法就是xxx<T, K, V>。
  3. 使用GenericTypeParameterBuilder來添加泛型約束。
  4. 用MethodBuilder的SetParameters或者SetReturnType或者SetSignature定義方法的傳回值和參數類型。這裡可以加入泛型型別:GenericTypeParameterBuilder或者非泛型型別Type。由於GenericTypeParameterBuilder也是繼承與Type的。
  5. 用ILGenerator產生方法IL內容。整個方法定義結束。

 

有必要再次強調就是GenericTypeParameterBuilder也是繼承與Type的,所以調用MethodBuilder的SetParameters或者SetReturnType或者SetSignature方法時傳入的參數都是Type類型,此時可以傳入Type或者GenericTypeParameterBuilder來代表非泛型型別和泛型型別。

 

最後就是GenericTypeParameterBuilder類型中的方法可以定義泛型參數的約束。SetBaseTypeConstraint可以限制基類。SetInterfaceConstants限制執行的借口類型(可以有多個)。SetGenericParameterAttributes定義其他屬性(通過GenericParameterAttributes枚舉)。比如DefaultConstructorConstraint代表可調用的無參數認建構函式(相當於:new()約束),還有ReferenceTypeConstraint和NotNullableValueTypeConstraint代表class和struct約束!(GenericParameterAttributes枚舉還有其他值,這裡就不一一講述了,讀者參考MSDN)。

 

注意:

 

定義泛型方法只支援在MethodBuilder類型中,DynamicMethod類型不支援。

 

讓我們用反射Emit動態定義一個這樣的方法:

static T doo<T, K>(T a, int b, K c, double d)

    where T : class

    where K : ICloneable, new()

{

    return a;

}

 

代碼:

//+ using System.Reflection

//+ using System.Reflection.Emit

static void CreateMethod(TypeBuilder tb)

{

    //使用TypeBuilder.DefineMethod沒有定義參數和傳回值類型的重載

    var mbuilder = tb.DefineMethod("doo",

        MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static);

 

    //返回:GenericTypeParameterBuilder[]

    var gpas = mbuilder.DefineGenericParameters("T", "K");

 

    //設定T的約束

    gpas[0].SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint);

    //設定K的約束

    gpas[1].SetGenericParameterAttributes(GenericParameterAttributes.DefaultConstructorConstraint);

    gpas[1].SetInterfaceConstraints(typeof(ICloneable));

 

    //定義參數類型:(T a, int b, K c, double d)

    mbuilder.SetParameters(gpas[0], typeof(int), gpas[1], typeof(double));

    //定義傳回值類型:T

    mbuilder.SetReturnType(gpas[0]);

 

    //設定名稱(這一步不是必須,因為沒有參數名稱也可以執行,IL內使用參數位置來引用參數的)

    //注意索引值從1開始,0代表傳回值類型。

    mbuilder.DefineParameter(1, ParameterAttributes.None, "a");

    mbuilder.DefineParameter(2, ParameterAttributes.None, "b");

    mbuilder.DefineParameter(3, ParameterAttributes.None, "c");

    mbuilder.DefineParameter(4, ParameterAttributes.None, "d");

 

    //定義方法IL

    var ilgen = mbuilder.GetILGenerator();

    //return a;

    ilgen.Emit(OpCodes.Ldarg_0);

    ilgen.Emit(OpCodes.Ret);

}

 

動態產生程式集後在Reflector下開啟方法:

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.