zoukankan      html  css  js  c++  java
  • C#使用Emit生成构造函数和属性

    假设我们需要一个名叫Kitty的类,其在Pets程序集下。

    复制代码
     1     // specify a new assembly name
     2     var assemblyName = new AssemblyName("Pets");
     3 
     4     // create assembly builder
     5     var assemblyBuilder = AppDomain.CurrentDomain
     6       .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
     7 
     8     // create module builder
     9     var moduleBuilder = assemblyBuilder.DefineDynamicModule("PetsModule", "Pets.dll");
    10 
    11     // create type builder for a class
    12     var typeBuilder = moduleBuilder.DefineType("Kitty", TypeAttributes.Public);
    复制代码

    定义字段

    Kitty类包含两个私有字段_id和_name。用类型构造器来定义,

    1     var fieldId = typeBuilder.DefineField(
    2       "_id", typeof(int), FieldAttributes.Private);
    3     var fieldName = typeBuilder.DefineField(
    4       "_name", typeof(string), FieldAttributes.Private);

    定义构造函数

    Kitty类包含一个有两个参数的构造函数,参数一为整型id,参数而为字符串型name。构造函数内,将参数id赋值给私有字段_id,将参数name赋值给私有字段_name,

    复制代码
     1     Type objType = Type.GetType("System.Object");
     2     ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
     3 
     4     Type[] constructorArgs = { typeof(int), typeof(string) };
     5 
     6     var constructorBuilder = typeBuilder.DefineConstructor(
     7         MethodAttributes.Public, CallingConventions.Standard, constructorArgs);
     8     ILGenerator ilOfCtor = constructorBuilder.GetILGenerator();
     9 
    10     ilOfCtor.Emit(OpCodes.Ldarg_0);
    11     ilOfCtor.Emit(OpCodes.Call, objCtor);
    12     ilOfCtor.Emit(OpCodes.Ldarg_0);
    13     ilOfCtor.Emit(OpCodes.Ldarg_1);
    14     ilOfCtor.Emit(OpCodes.Stfld, fieldId);
    15     ilOfCtor.Emit(OpCodes.Ldarg_0);
    16     ilOfCtor.Emit(OpCodes.Ldarg_2);
    17     ilOfCtor.Emit(OpCodes.Stfld, fieldName);
    18     ilOfCtor.Emit(OpCodes.Ret); 
    复制代码

    定义属性

    为Kitty类创建Id和Name两个属性,读取和设置私有字段_id和_name。C#中的属性定义的getter和setter分别为两个方法。

    复制代码
     1     var methodGetId = typeBuilder.DefineMethod(
     2       "GetId", MethodAttributes.Public, typeof(int), null);
     3     var methodSetId = typeBuilder.DefineMethod(
     4       "SetId", MethodAttributes.Public, null, new Type[] { typeof(int) });
     5 
     6     var ilOfGetId = methodGetId.GetILGenerator();
     7     ilOfGetId.Emit(OpCodes.Ldarg_0); // this
     8     ilOfGetId.Emit(OpCodes.Ldfld, fieldId);
     9     ilOfGetId.Emit(OpCodes.Ret);
    10 
    11     var ilOfSetId = methodSetId.GetILGenerator();
    12     ilOfSetId.Emit(OpCodes.Ldarg_0); // this
    13     ilOfSetId.Emit(OpCodes.Ldarg_1); // the first one in arguments list
    14     ilOfSetId.Emit(OpCodes.Stfld, fieldId);
    15     ilOfSetId.Emit(OpCodes.Ret);
    16 
    17     // create Id property
    18     var propertyId = typeBuilder.DefineProperty(
    19       "Id", PropertyAttributes.None, typeof(int), null);
    20     propertyId.SetGetMethod(methodGetId);
    21     propertyId.SetSetMethod(methodSetId);
    22 
    23     var methodGetName = typeBuilder.DefineMethod(
    24       "GetName", MethodAttributes.Public, typeof(string), null);
    25     var methodSetName = typeBuilder.DefineMethod(
    26       "SetName", MethodAttributes.Public, null, new Type[] { typeof(string) });
    27 
    28     var ilOfGetName = methodGetName.GetILGenerator();
    29     ilOfGetName.Emit(OpCodes.Ldarg_0); // this
    30     ilOfGetName.Emit(OpCodes.Ldfld, fieldName);
    31     ilOfGetName.Emit(OpCodes.Ret);
    32 
    33     var ilOfSetName = methodSetName.GetILGenerator();
    34     ilOfSetName.Emit(OpCodes.Ldarg_0); // this
    35     ilOfSetName.Emit(OpCodes.Ldarg_1); // the first one in arguments list
    36     ilOfSetName.Emit(OpCodes.Stfld, fieldName);
    37     ilOfSetName.Emit(OpCodes.Ret);
    38 
    39     // create Name property
    40     var propertyName = typeBuilder.DefineProperty(
    41       "Name", PropertyAttributes.None, typeof(string), null);
    42     propertyName.SetGetMethod(methodGetName);
    43     propertyName.SetSetMethod(methodSetName);
    复制代码

    定义方法

    为Kitty类增加一个ToString()方法,返回一个字符串值。

    复制代码
     1     // create ToString() method
     2     var methodToString = typeBuilder.DefineMethod(
     3       "ToString",
     4       MethodAttributes.Virtual | MethodAttributes.Public,
     5       typeof(string),
     6       null);
     7 
     8     var ilOfToString = methodToString.GetILGenerator();
     9     var local = ilOfToString.DeclareLocal(typeof(string)); // create a local variable
    10     ilOfToString.Emit(OpCodes.Ldstr, "Id:[{0}], Name:[{1}]");
    11     ilOfToString.Emit(OpCodes.Ldarg_0); // this
    12     ilOfToString.Emit(OpCodes.Ldfld, fieldId);
    13     ilOfToString.Emit(OpCodes.Box, typeof(int)); // boxing the value type to object
    14     ilOfToString.Emit(OpCodes.Ldarg_0); // this
    15     ilOfToString.Emit(OpCodes.Ldfld, fieldName);
    16     ilOfToString.Emit(OpCodes.Call,
    17       typeof(string).GetMethod("Format",
    18       new Type[] { typeof(string), typeof(object), typeof(object) }));
    19     ilOfToString.Emit(OpCodes.Stloc, local); // set local variable
    20     ilOfToString.Emit(OpCodes.Ldloc, local); // load local variable to stack
    21     ilOfToString.Emit(OpCodes.Ret);
    复制代码

    保存类型

    生成类型,并保存程序集至Pets.dll文件。

    1     // then create the whole class type
    2     var classType = typeBuilder.CreateType();
    3 
    4     // save assembly
    5     assemblyBuilder.Save("Pets.dll");

    反编译类

    使用反编译器来查看生成的类,

    复制代码
     1 using System;
     2 public class Kitty
     3 {
     4   private int _id;
     5   private string _name;
     6   public int Id
     7   {
     8     get
     9     {
    10       return this._id;
    11     }
    12     set
    13     {
    14       this._id = value;
    15     }
    16   }
    17   public string Name
    18   {
    19     get
    20     {
    21       return this._name;
    22     }
    23     set
    24     {
    25       this._name = value;
    26     }
    27   }
    28   public Kitty(int id, string name)
    29   {
    30     this._id = id;
    31     this._name = name;
    32   }
    33   public override string ToString()
    34   {
    35     return string.Format("Id:[{0}], Name:[{1}]", this._id, this._name);
    36   }
    37 }
    复制代码

    完整代码

    复制代码
      1 using System;
      2 using System.Reflection;
      3 using System.Reflection.Emit;
      4 
      5 namespace EmitCreateMembers
      6 {
      7   class Program
      8   {
      9     static void Main(string[] args)
     10     {
     11       // specify a new assembly name
     12       var assemblyName = new AssemblyName("Pets");
     13 
     14       // create assembly builder
     15       var assemblyBuilder = AppDomain.CurrentDomain
     16         .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
     17 
     18       // create module builder
     19       var moduleBuilder = assemblyBuilder.DefineDynamicModule("PetsModule", "Pets.dll");
     20 
     21       // create type builder for a class
     22       var typeBuilder = moduleBuilder.DefineType("Kitty", TypeAttributes.Public);
     23 
     24       // then create whole class structure
     25       CreateKittyClassStructure(typeBuilder);
     26 
     27       // then create the whole class type
     28       var classType = typeBuilder.CreateType();
     29 
     30       // save assembly
     31       assemblyBuilder.Save("Pets.dll");
     32 
     33       Console.WriteLine("Hi, Dennis, a Pets assembly has been generated for you.");
     34       Console.ReadLine();
     35     }
     36 
     37     private static void CreateKittyClassStructure(TypeBuilder typeBuilder)
     38     {
     39       // ---- define fields ----
     40 
     41       var fieldId = typeBuilder.DefineField(
     42         "_id", typeof(int), FieldAttributes.Private);
     43       var fieldName = typeBuilder.DefineField(
     44         "_name", typeof(string), FieldAttributes.Private);
     45 
     46       // ---- define costructors ----
     47 
     48       Type objType = Type.GetType("System.Object");
     49       ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
     50 
     51       Type[] constructorArgs = { typeof(int), typeof(string) };
     52 
     53       var constructorBuilder = typeBuilder.DefineConstructor(
     54          MethodAttributes.Public, CallingConventions.Standard, constructorArgs);
     55       ILGenerator ilOfCtor = constructorBuilder.GetILGenerator();
     56 
     57       ilOfCtor.Emit(OpCodes.Ldarg_0);
     58       ilOfCtor.Emit(OpCodes.Call, objCtor);
     59       ilOfCtor.Emit(OpCodes.Ldarg_0);
     60       ilOfCtor.Emit(OpCodes.Ldarg_1);
     61       ilOfCtor.Emit(OpCodes.Stfld, fieldId);
     62       ilOfCtor.Emit(OpCodes.Ldarg_0);
     63       ilOfCtor.Emit(OpCodes.Ldarg_2);
     64       ilOfCtor.Emit(OpCodes.Stfld, fieldName);
     65       ilOfCtor.Emit(OpCodes.Ret);
     66 
     67       // ---- define properties ----
     68 
     69       var methodGetId = typeBuilder.DefineMethod(
     70         "GetId", MethodAttributes.Public, typeof(int), null);
     71       var methodSetId = typeBuilder.DefineMethod(
     72         "SetId", MethodAttributes.Public, null, new Type[] { typeof(int) });
     73 
     74       var ilOfGetId = methodGetId.GetILGenerator();
     75       ilOfGetId.Emit(OpCodes.Ldarg_0); // this
     76       ilOfGetId.Emit(OpCodes.Ldfld, fieldId);
     77       ilOfGetId.Emit(OpCodes.Ret);
     78 
     79       var ilOfSetId = methodSetId.GetILGenerator();
     80       ilOfSetId.Emit(OpCodes.Ldarg_0); // this
     81       ilOfSetId.Emit(OpCodes.Ldarg_1); // the first one in arguments list
     82       ilOfSetId.Emit(OpCodes.Stfld, fieldId);
     83       ilOfSetId.Emit(OpCodes.Ret);
     84 
     85       // create Id property
     86       var propertyId = typeBuilder.DefineProperty(
     87         "Id", PropertyAttributes.None, typeof(int), null);
     88       propertyId.SetGetMethod(methodGetId);
     89       propertyId.SetSetMethod(methodSetId);
     90 
     91       var methodGetName = typeBuilder.DefineMethod(
     92         "GetName", MethodAttributes.Public, typeof(string), null);
     93       var methodSetName = typeBuilder.DefineMethod(
     94         "SetName", MethodAttributes.Public, null, new Type[] { typeof(string) });
     95 
     96       var ilOfGetName = methodGetName.GetILGenerator();
     97       ilOfGetName.Emit(OpCodes.Ldarg_0); // this
     98       ilOfGetName.Emit(OpCodes.Ldfld, fieldName);
     99       ilOfGetName.Emit(OpCodes.Ret);
    100 
    101       var ilOfSetName = methodSetName.GetILGenerator();
    102       ilOfSetName.Emit(OpCodes.Ldarg_0); // this
    103       ilOfSetName.Emit(OpCodes.Ldarg_1); // the first one in arguments list
    104       ilOfSetName.Emit(OpCodes.Stfld, fieldName);
    105       ilOfSetName.Emit(OpCodes.Ret);
    106 
    107       // create Name property
    108       var propertyName = typeBuilder.DefineProperty(
    109         "Name", PropertyAttributes.None, typeof(string), null);
    110       propertyName.SetGetMethod(methodGetName);
    111       propertyName.SetSetMethod(methodSetName);
    112 
    113       // ---- define methods ----
    114 
    115       // create ToString() method
    116       var methodToString = typeBuilder.DefineMethod(
    117         "ToString",
    118         MethodAttributes.Virtual | MethodAttributes.Public,
    119         typeof(string),
    120         null);
    121 
    122       var ilOfToString = methodToString.GetILGenerator();
    123       var local = ilOfToString.DeclareLocal(typeof(string)); // create a local variable
    124       ilOfToString.Emit(OpCodes.Ldstr, "Id:[{0}], Name:[{1}]");
    125       ilOfToString.Emit(OpCodes.Ldarg_0); // this
    126       ilOfToString.Emit(OpCodes.Ldfld, fieldId);
    127       ilOfToString.Emit(OpCodes.Box, typeof(int)); // boxing the value type to object
    128       ilOfToString.Emit(OpCodes.Ldarg_0); // this
    129       ilOfToString.Emit(OpCodes.Ldfld, fieldName);
    130       ilOfToString.Emit(OpCodes.Call,
    131         typeof(string).GetMethod("Format",
    132         new Type[] { typeof(string), typeof(object), typeof(object) }));
    133       ilOfToString.Emit(OpCodes.Stloc, local); // set local variable
    134       ilOfToString.Emit(OpCodes.Ldloc, local); // load local variable to stack
    135       ilOfToString.Emit(OpCodes.Ret);
    136     }
    137   }
    138 }
    复制代码

    下载完整代码

    进一步了解使用Emit构造动态代理类

  • 相关阅读:
    python之pymysql的使用
    python 之 Apollo
    python 之 RabbitMQ
    python之内置sqlite3
    pyQt5之2048小游戏
    VSCode 下载速度慢问题解决
    Redis 缓存穿透 + 缓存雪崩 + 缓存击穿的原因和解决方案
    部门优化
    Cpu_Limit.sh
    Autoback-xtraback.sh
  • 原文地址:https://www.cnblogs.com/twinhead/p/9160975.html
Copyright © 2011-2022 走看看