通过Emit实现动态类生成

原创 2004年09月09日 08:39:00

动态生成一个类对于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这些“皮”依次构造出来:

 System;
 System.Reflection;
 System.Reflection.Emit;


  TypeCreator
{
     Type targetType;

    
    
    
    
     TypeCreator(Type targetType)
    {
        .targetType = targetType;
    }

     Type build()
    {
        
        AppDomain currentAppDomain = AppDomain.CurrentDomain;
        
    
        AssemblyName assyName =   AssemblyName();

        
        assyName.Name =  + targetType.Name;

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

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

        
        String newTypeName = +targetType.Name;

        
        TypeAttributes newTypeAttribute = TypeAttributes.Class | TypeAttributes.Public;

        
        Type newTypeParent;

        
        Type[] newTypeInterfaces;

        
        (targetType.IsInterface)    
       {
            newTypeParent = ;
            newTypeInterfaces =  Type[]{targetType};
       }
       
       {
            newTypeParent = targetType;
            newTypeInterfaces =  Type[0];
       }
    
       
        TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName,newTypeAttribute,newTypeParent,newTypeInterfaces);

       

        
        MethodInfo[] targetMethods = targetType.GetMethods();

       
        (MethodInfo targetMethod  targetMethods)
        {
           
            (targetMethod.IsVirtual)
            {
              
                ParameterInfo[] paramInfo = targetMethod.GetParameters();
              Type[] paramType =  Type[paramInfo.Length];
              ( i=0;i
                MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name,MethodAttributes.Public|MethodAttributes.Virtual,targetMethod.ReturnType,paramType);

              

                
                ILGenerator ilGen = methodBuilder.GetILGenerator();
              
ilGen.Emit(OpCodes.Ldstr,+ targetMethod.Name +); ilGen.Emit(OpCodes.Call,(Console).GetMethod(, Type[]{(String)})); ilGen.Emit(OpCodes.Ret); } } (typeBuilder.CreateType()); } }
 
好了,测试一下试试看:
 System;

  Tester
{
       Main(String[] args)
    {
        TypeCreator tc= TypeCreator((IAnimal));
        Type t = tc.build();
        IAnimal animal= (IAnimal)Activator.CreateInstance(t);
        animal.move();
        animal.eat();

        Console.Read ();
    }
}

得到输出:

通过 scikit-learn 实现情感分析

-
  • 1970年01月01日 08:00

.NET 动态接口代理探秘(NInterfaceProxy)

在JAVA中实现动态接口代理的方法有很多,但显然在.NET中相似的方法似乎挺难找的 当然这不是说你无法自己写出这方面的东西 它的确不会是个太难的东西 只是会相对麻烦些 对于动态接口代理对我们而言它具...
  • liulilittle
  • liulilittle
  • 2017-01-11 13:05:52
  • 427

使用Emit把IDataRecord转换为实体对象

Emit性能高,但是可读性差,不过在企业中值得推荐,我们就来看具体的转换代码吧 public class DynamicBuilder { private static readonly Me...
  • zhuqinfeng
  • zhuqinfeng
  • 2017-04-21 13:59:32
  • 382

C++ 高级数据类型(四)—— 动态内存分配

到目前为止,我们的程序中我们只用了声明变量、数组和其他对象(objects)所必需的内存空间,这些内存空间的大小都在程序执行之前就已经确定了。但如果我们需要内存大小为一个变量,其数值只有在程序运行时 ...
  • zqixiao_09
  • zqixiao_09
  • 2016-05-22 12:30:18
  • 1344

linux C++ 共享库导出类

linux C++ 共享库导出类 1.共享库的对外接口函数的声明必须加上extern “C”。 2.使用共享库对话接口函数生成的对象指针时在该对象未被释放之前不能关闭共享库句柄,否则会出现se...
  • huhuhaha008
  • huhuhaha008
  • 2014-09-14 16:56:03
  • 1321

C++学习笔记四之使用new来创建动态数组

【一】 1、静态联编:不管程序最终是否使用数组,数组都在那里,它占用了内存,在编译时给数组分配内存被称为静态联编。 2、动态联编:使用new时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建,...
  • mars_xiaolei
  • mars_xiaolei
  • 2017-07-07 15:07:04
  • 276

Linux上C++类的动态加载

Linux上C++类的动态加载 摘要:本文是翻译文章,主要介绍了运行时重载C++类的技术,包括了Linux上的动态加载接口、C++类的动态加载技术点及实现、自动加载技术等。最后给出了两个应用案例...
  • zdy0_2004
  • zdy0_2004
  • 2015-04-27 00:24:49
  • 1819

C++实现根据类名动态生成类对象

在开发后台服务的过程中,我们常常需要从数据库中取数据,并将数据缓存在本地中,另外,我们的服务还需要有更新数据的能力:包括定时的主动更新以及数据库数据更新时服务收到通知的被动更新。之前在需要用到以上功能...
  • jiange_zh
  • jiange_zh
  • 2016-08-09 22:33:22
  • 3884

C++动态类型与静态类型

大多数情况下对象的静态类型和动态类型相同,我们不用关系二者区别;只有多态情况下,即在有虚函数的继承体系中,通过基类的指针或引用调用虚函数时,这时我们就需要关系指针或引用对象的动态类型,因为它们的静态类...
  • qq_26849233
  • qq_26849233
  • 2017-07-21 15:00:45
  • 572

c++对象的动态创建与释放

1 new和delete基本语法 1)在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提...
  • bbs375
  • bbs375
  • 2016-09-22 16:52:33
  • 2891
收藏助手
不良信息举报
您举报文章:通过Emit实现动态类生成
举报原因:
原因补充:

(最多只允许输入30个字)