日期:2008-05-15  浏览次数:20509 次

动态生成一个类对于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;