国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java中通過Emit實現動態類生成

2019-11-18 15:39:44
字體:
來源:轉載
供稿:網友

  動態生成一個類對于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());
 }
}
  好了,測試一下試試看:



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 泸水县| 恩施市| 崇义县| 阳江市| 武宁县| 黎城县| 宁城县| 临朐县| 贵阳市| 鄂托克旗| 电白县| 新民市| 五华县| 舟曲县| 莱州市| 南澳县| 绥江县| 井研县| 定日县| 白沙| 繁峙县| 任丘市| 瑞丽市| 三江| 汤原县| 棋牌| 云林县| 汶上县| 吕梁市| 文水县| 邢台县| 乌拉特中旗| 万盛区| 洞头县| 镇雄县| 宣恩县| 汶川县| 任丘市| 凤凰县| 都安| 阿勒泰市|