c#中,可以使用Emit动态生成IL代码,其主要是为了解决:

  • 对方法的动态扩展
  • 优化反射速度

但是由于Emit的使用需要大量操作Opcodes,可能难以理解,因此可以使用一些NuGet包来辅助进行Emit操作。

使用

下载NuGet包:DynEmit。此包尚处于PreRelease状态,需要设置NuGet可见PreRelease。

基本使用

例如,我们需要获得Message类的PayLoad字段:

以下为Message定义:

public class Message
{
    public string Payload { get; } = "TestContent";
}

对于正常使用Emit来获取该字段,需要这样操作:

DynamicMethod methods = new DynamicMethod("method",typeof(string),new []{typeof(Message)});
var il = methods.GetILGenerator();
il.Emit(OpCodes.Ldarg,0);
il.Emit(OpCodes.Callvirt,typeof(Message).GetProperties()[0].GetMethod!);
il.Emit(OpCodes.Ret);
Delegate @delegate = methods.CreateDelegate(typeof(Func<Message, string>));
Console.WriteLine(@delegate.DynamicInvoke(new Message()));

但是在DynEmit下,我们可以避免使用OpCodes,而使用DynEmit封装好的方法:

DynEmitMethod<Func<Message,string>> method = new ("method");
var argument = method.LoadArgument(0);
var obj = argument.CastToLocalVariable(typeof(object));
var res = method.ActionNonStaticMethod(typeof(Message).GetProperties()[0].GetMethod!,(DynObject)obj,new())!;
res.PushValue();
method.Invoke(new Message());

缺点

由于DynEmit内部对OpCodes进行了封装,因此可能会出现一些冗余类,可能会比直接调用Emit要慢。

最后修改:2023 年 02 月 02 日
打点赏咯~