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构造动态代理类

 

posted @ 2013-06-01 16:07  sangmado  阅读(7721)  评论(4编辑  收藏  举报