Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法
上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了.
今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法.
来源:http://www.cnblogs.com/yingql/archive/2009/03/22/1419149.html
废话不多说了, 直接上示例
一、示例
我这边所用的示例跟来源中是一样的,请看代码:
public class Add
{ int numA = ;
public int NumA { get { return numA; } set { numA = value; } } int numB = ;
public int NumB { get { return NumB; } set { NumB = value; } } public Add(int a, int b)
{
numA = a;
numB = b;
} public int Calc()
{
return numA + numB;
}
}
我们要动态的创建这么一个类, 先不给你们看编码过程, 先给你们看结果吧, 先知道下, 这么做, 能大致得到一个什么结果.
运行代码之后, 会在bin里面得到一个 Elvin.dll 文件, 把这个文件和 ConsoleApplication2.exe 一起拿去反编译, 去看里面 Add 类的内容

比较下来, 原生的和动态生成的稍有不同, 里面的IL代码也会有部分不同,这个是正常的, 虽然是参照着反编译的代码写的, 但是只是参照, 不是完全相同的.
二、编码
先看几个主要的部分, 后面我会把完整的代码贴出来
1. 字段
private int numA; --> .field private int32 numA
var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private);
//fieldABuilder.SetConstant(0); 此处为副初始值, 这里可省略
没什么好解释的, 一眼就能看懂, 至于这个 typeBldr 暂且不去管它
2. 属性
//1.属性 public int NumA { get{return numA;} set{numA = value;} }
            var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None,
                CallingConventions.HasThis, typeof(Int32), null);
            //2. 定义 get, set 方法
        
            //2.1 get方法 代码部分和上图上的是有些不同的, 是参照着上图这个来的
            var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public |
                MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
            //ILGenerator
            var getAIL = getPropertyABuilder.GetILGenerator();
            getAIL.Emit(OpCodes.Ldarg_0);   //this
            getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA
            getAIL.Emit(OpCodes.Ret); //return numA
          
        
            //2.2 set方法 代码部分和上图中是不一样的, 是参照着上图来的
            var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public |
                MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
            //ILGenerator
            var setAIL = setPropertyABuilder.GetILGenerator();
            //setAIL.Emit(OpCodes.Nop);   //这句可省略
            setAIL.Emit(OpCodes.Ldarg_0);  //this
            setAIL.Emit(OpCodes.Ldarg_1);  //value
            setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value;
            setAIL.Emit(OpCodes.Ret);   //return;
            //3.绑定get,set方法到属性上
            propertyABuilder.SetGetMethod(getPropertyABuilder);
            propertyABuilder.SetSetMethod(setPropertyABuilder);
很多时候, 我们用的是匿名的属性, 如: public int NumA{get;set;}, 这种情况, 会自动生成一个匿名私有变量来代替numA, 去与之匹配, 属性的本质是方法, 并不能用来存储数据
3. 构造函数
IL代码:
.method public hidebysig specialname rtspecialname instance void .ctor(int32 a, int32 b) cil managed
{
.maxstack
L_0000: ldarg.
L_0001: ldc.i4.
L_0002: stfld int32 ConsoleApplication2.Add::numA
L_0007: ldarg.
L_0008: ldc.i4.
L_0009: stfld int32 ConsoleApplication2.Add::numB
L_000e: ldarg.
L_000f: call instance void [mscorlib]System.Object::.ctor()
L_0014: nop
L_0015: nop
L_0016: ldarg.
L_0017: ldarg.
L_0018: stfld int32 ConsoleApplication2.Add::numA
L_001d: ldarg.
L_001e: ldarg.
L_001f: stfld int32 ConsoleApplication2.Add::numB
L_0024: nop
L_0025: ret
} //定义构造函数 ConstructorBuilder
var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) });
var ctorIL = constructorBuilder.GetILGenerator();
// numA = a;
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Stfld, fieldABuilder);
//NumB = b;
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_2);
ctorIL.Emit(OpCodes.Stfld, fieldBBuilder);
ctorIL.Emit(OpCodes.Ret);
4. 方法
IL代码:
.method public hidebysig instance int32 Calc() cil managed
{
.maxstack
.locals init (
[] int32 num)
L_0000: nop
L_0001: ldarg.
L_0002: ldfld int32 ConsoleApplication2.Add::numA
L_0007: ldarg.
L_0008: ldfld int32 ConsoleApplication2.Add::numB
L_000d: add
L_000e: stloc.
L_000f: br.s L_0011
L_0011: ldloc.
L_0012: ret
} //8.定义方法 MethodBuilder
var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
var calcIL = calcMethodBuilder.GetILGenerator();
//加载私有字段numA
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldfld, fieldABuilder);
//加载属性NumB
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldfld, fieldBBuilder);
//想加并返回栈顶的值
calcIL.Emit(OpCodes.Add);
calcIL.Emit(OpCodes.Ret);
5. 到这里, 主要的部分就介绍完了, 下面给出检验的部分:
//9.结果
Type type = typeBldr.CreateType();
int a = ;
int b = ;
Object ob = Activator.CreateInstance(type, new object[] { a, b });
Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null));
执行之后, 会输出 "The Result of 2 + 3 is 5"
至此, 今天要介绍的部分就结束了, 我把自己学习的过程和结果贴出来, 供有兴趣的童鞋瞄一下.
以下是完整的代码
static void Main(string[] args)
{
//1.构建程序集
var asmName = new AssemblyName("Elvinle");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); //2.创建模块
var mdlBldr = asmBuilder.DefineDynamicModule("Elvin", "Elvin.dll"); //3.定义类, public class Add
var typeBldr = mdlBldr.DefineType("Add", TypeAttributes.Public | TypeAttributes.BeforeFieldInit); //4. 定义属性和字段
//4.1字段 FieldBuilder
var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private);
//fieldABuilder.SetConstant(0); 此处为副初始值, 这里可省略 var fieldBBuilder = typeBldr.DefineField("numB", typeof(Int32), FieldAttributes.Private); //4.2属性 PropertyBuilder
var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null); var propertyBBuilder = typeBldr.DefineProperty("NumB", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null); //5.定义属性numA的get;set;方法 MethodBuilder
//5.1 get方法
var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
//ILGenerator
GetPropertyIL(getPropertyABuilder, fieldABuilder);
//var getAIL = getPropertyABuilder.GetILGenerator();
//getAIL.Emit(OpCodes.Ldarg_0); //this
//getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA
//getAIL.Emit(OpCodes.Ret); //return numA //5.2 set方法
var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
//ILGenerator
SetPropertyIL(setPropertyABuilder, fieldABuilder);
//var setAIL = setPropertyABuilder.GetILGenerator();
////setAIL.Emit(OpCodes.Nop); //这句可省略
//setAIL.Emit(OpCodes.Ldarg_0); //this
//setAIL.Emit(OpCodes.Ldarg_1); //value
//setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value;
//setAIL.Emit(OpCodes.Ret); //return; //5.3 绑定
propertyABuilder.SetGetMethod(getPropertyABuilder);
propertyABuilder.SetSetMethod(setPropertyABuilder); //6.定义属性numA的get;set;方法 MethodBuilder
var getPropertyBBuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
GetPropertyIL(getPropertyBBuilder, fieldBBuilder); var setPropertyBBuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
SetPropertyIL(setPropertyBBuilder, fieldBBuilder); propertyBBuilder.SetGetMethod(getPropertyBBuilder);
propertyBBuilder.SetSetMethod(setPropertyBBuilder); //7.定义构造函数 ConstructorBuilder
var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) });
var ctorIL = constructorBuilder.GetILGenerator();
// numA = a;
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Stfld, fieldABuilder);
//NumB = b;
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_2);
ctorIL.Emit(OpCodes.Stfld, fieldBBuilder);
ctorIL.Emit(OpCodes.Ret); //8.定义方法 MethodBuilder
var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
var calcIL = calcMethodBuilder.GetILGenerator();
//加载私有字段numA
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldfld, fieldABuilder);
//加载属性NumB
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldfld, fieldBBuilder);
//相加并返回栈顶的值
calcIL.Emit(OpCodes.Add);
calcIL.Emit(OpCodes.Ret); //9.结果
Type type = typeBldr.CreateType();
int a = ;
int b = ;
Object ob = Activator.CreateInstance(type, new object[] { a, b });
Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null)); asmBuilder.Save("Elvin.dll");
Console.ReadKey();
} private static void GetPropertyIL(MethodBuilder getPropertyBuilder, FieldBuilder fieldBuilder)
{
//ILGenerator
var getAIL = getPropertyBuilder.GetILGenerator();
getAIL.Emit(OpCodes.Ldarg_0); //this
getAIL.Emit(OpCodes.Ldfld, fieldBuilder); //numA
getAIL.Emit(OpCodes.Ret); //return numA
} private static void SetPropertyIL(MethodBuilder setPropertyBuilder, FieldBuilder fieldBuilder)
{
//ILGenerator
var setAIL = setPropertyBuilder.GetILGenerator();
//setAIL.Emit(OpCodes.Nop); //这句可省略
setAIL.Emit(OpCodes.Ldarg_0); //this
setAIL.Emit(OpCodes.Ldarg_1); //value
setAIL.Emit(OpCodes.Stfld, fieldBuilder); //numA = value;
setAIL.Emit(OpCodes.Ret); //return;
}
希望我在学习的过程中, 也能带给你们一些不同的东西!
Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法的更多相关文章
- 我的Python学习笔记(四):动态添加属性和方法
		
一.动态语言与静态语言 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C ...
 - day_5.26python动态添加属性和方法
		
python动态添加属性和方法 既然给类添加⽅法,是使⽤ 类名.⽅法名 = xxxx ,那么给对象添加⼀个⽅法 也是类似的 对象.⽅法名 = xxx '''2018-5-26 13:40:09pyth ...
 - js对象动态添加属性,方法
		
1. 动态添加属性,方法 var object = new Object(); object.name = "name"; object.age = 19; >>> ...
 - ios开发runtime学习四:动态添加属性
		
#import "ViewController.h" #import "Person.h" #import "NSObject+Property.h& ...
 - Python笔记_第三篇_面向对象_8.对象属性和类属性及其动态添加属性和方法
		
1. 对象属性和类属性. 我们之前接触到,在类中,我们一般都是通过构造函数的方式去写一些类的相关属性.在第一次介绍类的时候我们把一些属性写到构造函数外面并没有用到构造函数,其实当时在写的时候,就是在给 ...
 - JS内置对象的原型不能重定义?只能动态添加属性或方法?
		
昨天马上就快下班了,坐在我对面的同事突然问我一个问题,我说“爱过”,哈哈,开个玩笑.情况是这样的,他发现JS的内置对象的原型好像不能通过字面量对象的形式进行覆盖, 只能动态的为内置对象的原型添加属性或 ...
 - python 动态添加属性及方法及“__slots__的作用”
		
1.动态添加属性 class Person(object): def __init__(self, newName, newAge): self.name = newName self.age = n ...
 - python动态添加属性和方法
		
---恢复内容开始--- python动态添加属性: class Person(object): def __init__(self,newName,newAge): self.name = newN ...
 - Python基础之动态添加属性,方法,动态类,静态类
		
## 动态添加属性class Person: def __init__(self,name): self.name = name# 1.通过对象.属性名称来操作p = Person('KTModel' ...
 
随机推荐
- Expression Tree 扩展MVC中的 HtmlHelper 和 UrlHelper
			
表达式树是LINQ To everything 的基础,同时各种类库的Fluent API也 大量使用了Expression Tree.还记得我在不懂expression tree时,各种眼花缭乱的A ...
 - 分享最新的博客到LinkedIn Timeline
			
使用Octopress作为我的博客框架有两年了.使用起来一直很顺手,这个工具真正的把博客跟写代码等同起来,非常酷炫.再加上各种各样的定制化,简直是随心所欲.我针对自己的需求对Octopress框架进行 ...
 - 创业6&7
			
周末两天泡咖啡店. 起不来,只好下午去. 周六5点到9点. 周日3点到12点. 1)整理直播课程讲义.完成50%. 2)修改GMTC演讲稿.完成. 招行的单子还是拒了,目前还没准备好高可用的App服务 ...
 - 自制操作系统 (三) 从启动区执行操作系统并进入C世界
			
qq:992591601 欢迎交流 2016.04.03 2016.05.31 2016.06.29 这一章是有些复杂的,我不太懂作者为什么要把这么多内容都放进一天. 1读入了十个柱面 2从启动区执行 ...
 - 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码
			
正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...
 - 百度面试题 字符串相似度 算法 similar_text 和页面相似度算法
			
在百度的面试,简直就是花样求虐. 首先在面试官看简历的期间,除了一个自己定义字符串相似度,并且写出求相似度的算法. ...这个确实没听说过,php的similar_text函数也是闻所未闻的.之前看s ...
 - YaHoo  前端优化军规
			
1.Minimize HTTP Requests 减少HTTP请求 图片.css.script.flash等等这些都会增加http请求数,减少这些元素的数量就能减少响应时间.把多个JS.CSS在可能的 ...
 - 学习ASP.NET MVC(二)——我的第一个ASP.NET MVC 控制器
			
MVC全称是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范,用一种业务逻辑和数据显示分离的方法组织代码,将 ...
 - java异常处理:建立exception包,建立Bank类,类中有变量double  balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),
			
建立exception包,建立Bank类,类中有变量double balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount ...
 - css text-align-last设置末尾文本对齐方式
			
text-align-last:auto | start | end | left | right | center | justify auto: 无特殊对齐方式. left: 内容左对齐. cen ...