通过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 ();
    }
}

得到输出:

Emit学习-基础篇-为动态类添加属性、构造函数、方法

Emit学习-基础篇-为动态类添加属性、构造函数、方法 我们通过一个计算A+B的动态类来演示如何为一个动态类添加属性、构造函数、方法,以及在方法中使用类中定义的属性,按照惯例,我们先给出要实...
  • wl58796351
  • wl58796351
  • 2013年03月24日 18:41
  • 1095

自用的基于Emit的C#下DataTable转实体类方法

自用的基于Emit的C#下DataTable转实体类方法之前一直在做WebForm的开发,数据绑定时直接DataTable绑定Gridview很方便,但是最近开始往MVC转,数据列表的传递和页面展示基...
  • vfeihuang
  • vfeihuang
  • 2017年01月05日 19:11
  • 872

属性值动态获取和赋值(反射、表达式、Emit)

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst...
  • DilemmaVF
  • DilemmaVF
  • 2017年03月24日 19:55
  • 895

node.js认识学习一:socke.io.emit 方法

emit可以很方便的发送数据,例如: socket.emit('action');表示发送了一个action命令,命令是字符串的,在另一端接收时,可以这么写: socket.on('action',...
  • u013864585
  • u013864585
  • 2015年05月25日 20:39
  • 1716

动态代理方式实现AOP

动态代理方式实现AOP 摘要:面向对象的思想强调"一切皆是对象",在面向对象的程序中我们使用真实概念的模型思考问题,使得整个软件系统开发可以像搭建房屋一样有条不紊。然而面向对象也并非完美无缺的,它更...
  • wu_qionglei
  • wu_qionglei
  • 2013年03月01日 12:08
  • 636

[AngularJS面面观] 10. scope事件机制 - $emit,$broadcast以及事件对象

发布-订阅模式(Publish-Subscribe Pattern) 事件的生命周期-注册和注销 事件与scope继承树-$emit以及$broadcast 事件的停止传播以及阻止默认行为 事件在sc...
  • dm_vincent
  • dm_vincent
  • 2016年07月10日 22:50
  • 5477

Emit常用Opcodes指令使用方法(含实例)

本人是从0开始学习Emit的,在学习过程中比较困扰我的就是有很多指令不理解、不会用,查了很多资料最终算是搞明白了,记录下来供大家参考。...
  • xiaouncle
  • xiaouncle
  • 2016年10月22日 11:34
  • 1989

PyQt5学习笔记06----Qt Designer自定义信号emit及传参

from PyQt5 import QtWidgets,QtCore   from untitled import Ui_Form   import  time        class My...
  • swartz_lubel
  • swartz_lubel
  • 2017年10月20日 22:50
  • 192

vuejs2.0实现分页组件,使用$emit进行事件监听数据传递

上一篇文章介绍了vuejs实现的简单分页,如果我有几个页面都需要有分页效果,不可能每个页面都去复制一下这段代码吧,意思是封装一下,变成通用的组件。https://segmentfault.com/a/...
  • sinat_17775997
  • sinat_17775997
  • 2017年02月23日 08:38
  • 4086

socket.io emit的几种用法解释

// send to current request socket client socket.emit('message', "this is a test"); // sending to al...
  • nathanhuang1220
  • nathanhuang1220
  • 2014年11月21日 14:08
  • 12912
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:通过Emit实现动态类生成
举报原因:
原因补充:

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