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 成功了。
分类:
Emit
标签:
Emit delegate 委托
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库