,Java   工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛,Java
您的位置:软件 > 开发者网络 > 开发工具 > Java > 正文
Java中通过Emit实现动态类生成
[文章信息]
作者:不详
时间:2005-04-09
出处:爱雪儿工作室
责任编辑:方舟
[文章导读]
动态生成一个类对于AOP,O/R Mapping等技术非常有帮助
advertisement
专题教程宝典
【软件应用】
【办公软件】
【图形图像】
【网页制作】
【操作系统】
【网络安全】
【程序开发】
【日报周刊】
【多媒体教程】
· 天极软件应用多媒体教程
· 游戏开发新手入门讲座
· 多媒体系列教程:网页设计制作
· 豪杰超级解霸V9使用手册(下)
· 打造个性化的Windows操作系统
· 图解Photoshop CS2 新功能体验
· 编程中的“拿来主义” 第三方控件推荐
· JBuilder 2005 单元测试体验
· 豪杰超级解霸V9使用手册(上)
· 数码照片后期处理与创意设计
[正文]
  动态生成一个类对于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 moveingI'm eating。

  总结

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

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
天极社区邀请您:写博客日记  上传相片   论坛聊天  订阅电子杂志  推荐网摘   免费图铃工具
笔名:   请您注意:

 遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。

 天极网拥有管理笔名和留言的一切权利。
评论:
 
,Java相关内容,Java焦点新闻
  • 用Java Swing作一个日历控制程序
  • Weblogic81和Hibernate 的集成问题
  • Java秘史:隐藏在SWT/Swing背后的故事
  • Struts+Spring+Hibernate快速入门
  • 用Eclipse进行可视化Java界面设计
  • FVD刺激高清碟机加速商业化 抢占商机最重要
  • 3家搜索引擎集体诉讼8848 吕春维未敢出席
  • 杨元庆:没有准备不会获批的备用方案
  • 军队信息化诞生新领域 电子军务呼之欲出
  • 世界经济论坛公布信息化程度全球最新排名
  • 2004政务绩效评估:政府门户尚处于发展阶段
  • 甲骨文出资5.15亿美元 意图收购RetekInc
  • 技术并购:帮你突破传统增长的“天花板”
  • ,JavaAdvertisement

    天极无线
    经典名曲 华语流行 欧美风情 人声音效 原声大碟
    你好周杰伦-安又琪
    直线-张韶涵
    天边-张韶涵
    看我72变-蔡依林
    乱世佳人-Twins
    全世界下雨-张娜拉
    我们的爱-飞儿乐队
    分手快乐-梁静茹
    爱在西元前-周杰伦
    三万英尺-迪克牛仔
    爱如潮水-张信哲
    爱情宣言-齐秦
    寻找玛依拉-刀郎
    驼铃-刀郎
    老鼠爱大米-杨臣刚
    功夫主题曲
    仙剑主题曲杀破狼
    天下无贼片尾曲
    冲动的惩罚-刀郎
    情人-刀郎
    爱情-莫文蔚
    挪威的森林-伍佰
    奔跑 - 羽泉
    因为爱 - 羽泉
      ·时尚女人圈
    ·经典影视专集
    ·美女秀场
    ·美丽大自然专题
    ·流行金曲
    ·科幻电影特区
    | 最新推荐
    ·你好周杰伦
    ·杀破狼
    ·寻找玛依拉
    ·孤单公园
    ·男人海洋
    | 魔术铃声
    ·少女丰胸
    ·少妇丰胸
    ·减肥魔铃
    ·增高魔铃
    ·美容魔铃

    今日报价查询 更多报价