分享
 
 
 

通过Emit实现动态类生成

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

动态生成一个类对于AOP,O/R Mapping等技术非常有帮助。对于Java来说,问题不大,而对于.NET,则要麻烦些(主要麻烦在于实现代码的生成需要IL),故猜测这可能也是在AOP, O/R Mapping方面,Java走得略前的原因吧。

麻烦归麻烦,非不能也,动态生成一个简单的类还不至于太难。

假设有如下接口:

interface IAnimal

{

void move();

void eat();

}

希望能创建一个类生成器TypeCreator,并能以以下方式使用:

TypeCreator tc=new TypeCreator(typeof(IAnimal));

Type t = tc.build();

IAnimal myAnimal= (IAnimal)Activator.CreateInstance(t);

myAnimal.move();

myAnimal.eat();

首先,发现System.Reflection.Emit.TypeBuilder似乎就是一个现成的类生成器。 不过TypeBuilder既没有实用的static方法,也不能在外部实例化。不过ModuleBuilder倒有一个DefineType()方法,可以得到TypeBuilder;而ModuleBuilder和TyperBuilder一个德行,不能直接创建,得从AssemblyBuilder的DefineDynamicModule()方法得到。追根溯源,AssemblyBuilder得从AppDomain的DefineDynamicAssembly()的得来。最终好在AppDomain提供了一个静态方法:AppDomain.CurrentDomain. 这一连串并非没有道理,类型是依附于Module的,而Module依附于Assembly,而Assembly则被AppDomain装载。所谓“皮之不存,毛将焉附”,为了创建Type这个“毛”,得先把Assembly,Module这些“皮”依次构造出来:

using System;

using System.Reflection;

using System.Reflection.Emit;

public class TypeCreator

{

private Type targetType;

/// <summary>

/// 构造函数

/// </summary>

/// <param name="targetType">被实现或者继承的类型</param>

public TypeCreator(Type targetType)

{

this.targetType = targetType;

}

public Type build()

{

//获取当前AppDomain

AppDomain currentAppDomain = AppDomain.CurrentDomain;

//System.Reflection.AssemblyName 是用来表示一个Assembly的完整名称的

AssemblyName assyName = new AssemblyName();

//为要创建的Assembly定义一个名称(这里忽略版本号,Culture等信息)

assyName.Name = "MyAssyFor_" + targetType.Name;

//获取AssemblyBuilder

//AssemblyBuilderAccess有Run,Save,RunAndSave三个取值

AssemblyBuilder assyBuilder = currentAppDomain.DefineDynamicAssembly(assyName,AssemblyBuilderAccess.Run);

//获取ModuleBuilder,提供String参数作为Module名称,随便设一个

ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule("MyModFor_"+targetType.Name);

//新类型的名称:随便定一个

String newTypeName = "Imp_"+targetType.Name;

//新类型的属性:要创建的是Class,而非Interface,Abstract Class等,而且是Public的

TypeAttributes newTypeAttribute = TypeAttributes.Class | TypeAttributes.Public;

//声明要创建的新类型的父类型

Type newTypeParent;

//声明要创建的新类型要实现的接口

Type[] newTypeInterfaces;

//对于基类型是否为接口,作不同处理

if(targetType.IsInterface)

{

newTypeParent = null;

newTypeInterfaces = new Type[]{targetType};

}

else

{

newTypeParent = targetType;

newTypeInterfaces = new Type[0];

}

//得到类型生成器

TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName,newTypeAttribute,newTypeParent,newTypeInterfaces);

//以下将为新类型声明方法:新类型应该override基类型的所以virtual方法

//得到基类型的所有方法

MethodInfo[] targetMethods = targetType.GetMethods();

//遍历各个方法,对于Virtual的方法,获取其签名,作为新类型的方法

foreach(MethodInfo targetMethod in targetMethods)

{

//只挑出virtual的方法

if(targetMethod.IsVirtual)

{

//得到方法的各个参数的类型

ParameterInfo[] paramInfo = targetMethod.GetParameters();

Type[] paramType = new Type[paramInfo.Length];

for(int i=0;i<paramInfo.Length;i++)

paramType[i] = paramInfo[i].ParameterType;

//传入方法签名,得到方法生成器

MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name,MethodAttributes.Public|MethodAttributes.Virtual,targetMethod.ReturnType,paramType);

//由于要生成的是具体类,所以方法的实现是必不可少的。而方法的实现是通过Emit IL代码来产生的

//得到IL生成器

ILGenerator ilGen = methodBuilder.GetILGenerator();

//以下三行相当于:{Console.Writeln("I'm "+ targetMethod.Name +"ing");}

ilGen.Emit(OpCodes.Ldstr,"I'm "+ targetMethod.Name +"ing");

ilGen.Emit(OpCodes.Call,typeof(Console).GetMethod("WriteLine",new Type[]{typeof(String)}));

ilGen.Emit(OpCodes.Ret);

}

}

//真正创建,并返回

return(typeBuilder.CreateType());

}

}

好了,测试一下试试看:

using System;

public class Tester

{

public static void Main(String[] args)

{

TypeCreator tc=new TypeCreator(typeof(IAnimal));

Type t = tc.build();

IAnimal animal= (IAnimal)Activator.CreateInstance(t);

animal.move();

animal.eat();

Console.Read ();

}

}

得到输出:

I'm moveing

I'm eating

总结:

如果用于AOP的话,Emit可以动态生成一个装饰类,相比于基于Remoting架构的TP/RP的方法,效率可能要高些,而且还能拦截new操作符。缺点:对于非Virtual的方法,似乎无法拦截。

用于O/R Mapping的类生成,倒是不错

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有