• Emit进阶 创建自定义委托Delegate


    随着上次对Emit的研究,对MSIL和Emit有了进一步了解,不过为了更好地实现Aop需要自己定义委托,但是Emit定义委托就没有类这么容易理解,在多次对照IL代码后,终于成功的实现了自定义委托Delegate。

    首先来看看一般的委托定义方法。

    public delegate string MyDelegate(string message);

    MSDN定义,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法。

    但是委托的本质是一个由系统自动生成的类,我们首先看看IL里面的MyDelegate的结构

    可以看到实际上MyDelegate是继承自MulticastDelegate的类

    MSIL表示方式如下:

    .class public auto ansi sealed EmitDemo.DelegateDemo.MyDelegate
    extends [mscorlib]System.MulticastDelegate
    {
    } // end of class EmitDemo.DelegateDemo.MyDelegate


    .method public hidebysig specialname rtspecialname
    instance void .ctor(object 'object',
    native int 'method') runtime managed
    {
    } // end of method MyDelegate::.ctor

    .method public hidebysig newslot virtual
    instance string Invoke(string message) runtime managed
    {
    } // end of method MyDelegate::Invoke

    不考虑异步调用,实际的类大概是这样的表示形式,但是C#并不允许直接继承MulticastDelegate,所以编译是无法通过的。

    public class MyDelegate:MulticastDelegate
    {
    public MyDelegate(object target,IntPtr method)
    :base(target,method)
    {

    }

    public override string Invoke(string message){}
    }

    接下来仿照这个定义来实现委托类

    首先是moduleBuilder 经常使用Emit的应该很熟悉了

               string name = "MyDelegateDemo";
    string fileName = name + ".dll";
    var assemblyName = new AssemblyName(name);
    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
    AssemblyBuilderAccess.RunAndSave);
    var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, fileName);


    接下来是定义类,要点是修饰参数要一致,基类是MulticastDelegate

     //public auto ansi sealed
    var delegateBuilder = moduleBuilder.DefineType("MyDelegate",
    TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
    TypeAttributes.Sealed, typeof(MulticastDelegate));


    在设置构造函数,修饰参数也要一致,函数参数为object和IntPtr

    最重要的是最后一句设置方法实现标志为runtime

      //            .method public hidebysig specialname rtspecialname 
    // instance void .ctor(object 'object',
    // native int 'method') runtime managed
    //{
    //} // end of method MyDelegate::.ctor

    var constructorBuilder = delegateBuilder.DefineConstructor(
    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
    MethodAttributes.RTSpecialName,
    CallingConventions.Standard, new[] { typeof(object), typeof(IntPtr) }
    );
    constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime);


    然后是定义方法Invoke,这里定义的返回值和参数都是string 可以根据需要调整。

    同样修饰要一致,最后也要设置方法实现标志为Runtime

     //            .method public hidebysig newslot virtual 
    // instance string Invoke(string message) runtime managed
    //{
    //} // end of method MyDelegate::Invoke
    var resultType = typeof(string);
    var paramTypes = new[] { typeof(string) };
    var methodBuilder = delegateBuilder.DefineMethod("Invoke",
    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
    MethodAttributes.Virtual,
    CallingConventions.Standard, resultType, paramTypes);
    methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime);

    最后创建类型,好了,定义完成了。

    var delegateType = delegateBuilder.CreateType();


    接下来就需要调用测试一下了。

    注意不能用Activator.CreateInstance()来初始化代理而是Delegate.CreateDelegate。

    public class MyClass
    {

    public string MyMethod(string message)
    {
    Console.WriteLine(message);
    return message;
    }

    }

    调用

     MyClass myClass = new MyClass();
    var myDelegate = Delegate.CreateDelegate(delegateType, myClass, "MyMethod");
    myDelegate.DynamicInvoke("Hello World!");

    结果 Hello World!

    OK 成功了。




     

  • 相关阅读:
    dubbo学习(一)认识
    MySQL学习(九)小结
    MySQL学习(八)删除表数据
    MySQL学习(六)change-buffer
    RPC 学习(一)认识
    MySQL学习(五)事务隔离
    MySQL学习(四)死锁及死锁检测
    计算机操作系统 --- 进程和进程的上下文切换
    MySQL 学习(三)事务学习
    消息队列(七)--- RocketMQ延时发送和消息重试(半原创)
  • 原文地址:https://www.cnblogs.com/kiminozo/p/2294711.html
Copyright © 2020-2023  润新知