Emit进阶 创建自定义委托Delegate

本文详细阐述了如何通过Emit实现自定义委托Delegate的过程,并提供了从一般委托定义到自定义类的完整步骤,包括构造函数和方法实现。通过实例测试验证了自定义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!");
 
  
 public class ClassDelagate
    {

        public ClassDelagate()
        {
            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);

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

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

            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();


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

    }

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


 
   
 

结果 Hello World!

OK 成功了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值