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

 





本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/archive/2013/06/01/csharp_emit_create_constructor_properties.html,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
7月前
|
存储 开发框架 编译器
C#OOP之六 构造函数和析构函数
C#OOP之六 构造函数和析构函数
18 0
|
7月前
|
C#
C# 继承类中(父类与子类)构造函数的调用顺序
C# 继承类中(父类与子类)构造函数的调用顺序
|
C# Windows 容器
C#或Winform中的消息通知之系统托盘的气泡提示窗口(系统toast通知)、ToolTip控件和ToolTipText属性
NotifyIcon控件表示系统右下角任务栏上的托盘图标,其ShowBalloonTip方法用于显示气球状提示框(Win10只有为本地Toast通知),ToolTip\oolTipText可以...
1471 0
C#或Winform中的消息通知之系统托盘的气泡提示窗口(系统toast通知)、ToolTip控件和ToolTipText属性
|
1月前
|
Java C#
C#学习相关系列之多线程(七)---Task的相关属性用法
C#学习相关系列之多线程(七)---Task的相关属性用法
|
1月前
|
编译器 C#
c#学习相关系列之构造函数
c#学习相关系列之构造函数
|
3月前
|
程序员 C#
C# 面向对象编程进阶:构造函数详解与访问修饰符应用
构造函数是一种特殊的方法,用于初始化对象。构造函数的优势在于,在创建类的对象时调用它。它可以用于为字段设置初始值
46 1
|
3月前
|
开发框架 .NET C#
C# 10.0中的扩展属性与模式匹配:深入解析
【1月更文挑战第20天】C# 10.0引入了众多新特性,其中扩展属性与模式匹配的结合为开发者提供了更强大、更灵活的类型检查和代码分支能力。通过这一特性,开发者可以在不修改原始类的情况下,为其添加新的行为,并在模式匹配中利用这些扩展属性进行更精细的控制。本文将详细探讨C# 10.0中扩展属性与模式匹配的工作原理、使用场景以及最佳实践,帮助读者更好地理解和应用这一新功能。
|
3月前
|
运维 编译器 C#
C# 9.0中的本地函数属性:深化函数级别的控制
【1月更文挑战第17天】C# 9.0引入了本地函数属性的概念,允许开发者在本地函数上应用属性,从而进一步细化对函数行为的控制。这一新特性不仅增强了代码的可读性和可维护性,还为函数级别的编程提供了更多的灵活性。本文将探讨C# 9.0中本地函数属性的用法、优势以及可能的应用场景,帮助读者更好地理解并应用这一新功能。
|
4月前
|
XML 存储 JSON
C# | 使用Json序列化对象时忽略只读的属性
将对象序列化成为Json字符串是一个使用频率非常高的功能。Json格式具有很高的可读性,同时相较于XML更节省空间。 在开发过程中经常会遇到需要保存配置的场景,比如将配置信息保存在配置类型的实例中,再将这个对象序列化成为Json字符串并保存。当需要加载配置时,则是读取Json格式的字符串再将其还原成配置对象。在序列化的过程中,默认会将所有公开的属性和字段都序列化进入Json字符串中,这其中也会包含只读的属性或字段,而只读的属性和字段在反序列化的过程中其实是无意义的,也就是说这一部分存储是多余的。 本文将讲解如何在执行Json序列化时,忽略掉那些只读的属性和字段。
53 0
C# | 使用Json序列化对象时忽略只读的属性