Java中通过Emit实现动态类生成
当前位置:以往代写 > JAVA 教程 >Java中通过Emit实现动态类生成
2019-06-14

Java中通过Emit实现动态类生成

Java中通过Emit实现动态类生成

副标题#e#

动态生成一个类对付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());
 }
}


#p#副标题#e#

好了,测试一下试试看:

#p#分页标题#e#

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 moveingI’m eating。

总结

假如用于AOP的话,Emit可以动态生成一个装饰类,对比于基于Remoting架构的TP/RP的要领,效率大概要高些,并且还能拦截new操纵符。缺点:对付非Virtual的要领,好像无法拦截。用于O/R Mapping的类生成,倒是不错。

    关键字:

在线提交作业