从 MethodInfo 生成 DynamicMethod

发布于 2024-09-07 06:46:41 字数 1224 浏览 2 评论 0原文

我正在研究 Joel Pobar 的避开常见的性能陷阱来制作快速的应用程序 关于反射的文章,我正在查看一段未编译的特定代码(稍微修改以缩小特定错误的范围,因为他的示例有更多错误):

MethodInfo writeLine = typeof(Console).GetMethod("WriteLine");
RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
DynamicMethod dm = new DynamicMethod(
    "HelloWorld",          // name of the method
    typeof(void),          // return type of the method
    new Type[]{},          // argument types for the method
    false);                // skip JIT visibility checks

ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello, world");
il.Emit(OpCodes.Call, myMethodHandle); // <-- 2 errors here
il.Emit(OpCodes.Ret);

错误是:

Program.cs(350,13): error CS1502: The best overloaded method match for 'System.Reflection.Emit.ILGenerator.Emit(System.Reflection.Emit.OpCode, byte)' has some invalid arguments
Program.cs(350,35): error CS1503: Argument '2': cannot convert from 'System.RuntimeMethodHandle' to 'byte'

ILGenerator 可以使用 MethodInfoEmit,但它似乎不支持 MethodHandle...有人知道如何让这个示例工作吗?

I was going over a Joel Pobar's Dodge Common Performance Pitfalls to Craft Speedy Applications article on Reflection and I was looking at a particular piece of code that isn't compiling (slightly modified to narrow down to the specific error, because his example had more errors):

MethodInfo writeLine = typeof(Console).GetMethod("WriteLine");
RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
DynamicMethod dm = new DynamicMethod(
    "HelloWorld",          // name of the method
    typeof(void),          // return type of the method
    new Type[]{},          // argument types for the method
    false);                // skip JIT visibility checks

ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello, world");
il.Emit(OpCodes.Call, myMethodHandle); // <-- 2 errors here
il.Emit(OpCodes.Ret);

The errors are:

Program.cs(350,13): error CS1502: The best overloaded method match for 'System.Reflection.Emit.ILGenerator.Emit(System.Reflection.Emit.OpCode, byte)' has some invalid arguments
Program.cs(350,35): error CS1503: Argument '2': cannot convert from 'System.RuntimeMethodHandle' to 'byte'

The ILGenerator can Emit with a MethodInfo, but it doesn't seem to support MethodHandle... does anybody know how to get this sample to work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

舟遥客 2024-09-14 06:46:41

像这样吗?

        MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] {typeof(string)});
        RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
        DynamicMethod dm = new DynamicMethod(
            "HelloWorld",          // name of the method
            typeof(void),          // return type of the method
            new Type[] { },          // argument types for the method
            false);                // skip JIT visibility checks

        ILGenerator il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldstr, "Hello, world");
        il.EmitCall(OpCodes.Call, writeLine, null);
        il.Emit(OpCodes.Ret);
        // test it 
        Action act = (Action)dm.CreateDelegate(typeof(Action));
        act();

更改:

  • 我使用调整后的 GetMethod 来查找 (string) 重载(否则它是一个不明确的匹配)
  • 使用 MethodInfo,而不是句柄(因为这就是 ILGenerator 想要的)
  • 使用 EmitCall (另一个也可能有效,但我知道这种方式有效)

Like so?

        MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] {typeof(string)});
        RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
        DynamicMethod dm = new DynamicMethod(
            "HelloWorld",          // name of the method
            typeof(void),          // return type of the method
            new Type[] { },          // argument types for the method
            false);                // skip JIT visibility checks

        ILGenerator il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldstr, "Hello, world");
        il.EmitCall(OpCodes.Call, writeLine, null);
        il.Emit(OpCodes.Ret);
        // test it 
        Action act = (Action)dm.CreateDelegate(typeof(Action));
        act();

Changes:

  • I used a tweaked GetMethod to find the (string) overload (otherwise it is an ambiguous match)
  • use the MethodInfo, not the handle (since that is what ILGenerator wants)
  • use EmitCall (the other might have worked too, but I know this way works)
小忆控 2024-09-14 06:46:41

通过 Nuget.org 上的这个库:
ClassWrapper

它为内部使用动态生成方法的类型创建包装器。因此,没有使用反射(仅进入 ClassWrapperDescriptor.Load 方法来生成动态表达式)

给定,例如名为 SampleClass 的类,

//Create the class wrapper descriptor, this can be cached and reused!
var classWrapperDescriptor = new ClassWrapperDescriptor(typeof(SampleClass));
//Initialize the descriptor
classWrapperDescriptor.Load();

//Create the instance of our object
object instance = new SampleClass();

//Create an instance of the wrapper
var classWrapper = classWrapperDescriptor.CreateWrapper(instance);

//Set a property
classWrapper.Set("StringProperty","test");

//Get a property
var stringPropertyValue = classWrapper.Get<string>("StringProperty");

//Invoke a method without return statement
classWrapper.Invoke("ParamMethod", "paramValue");

//Invoke a method witho return statement
var result = classWrapper.Invoke<int>("ReturnMethod", "paramValue");

非常感谢有关此库的任何反馈!

Through this library on Nuget.org:
ClassWrapper

It creates wrappers for types that internally uses dynamically generated methods. So no reflection used (only into the ClassWrapperDescriptor.Load method to generate the dynamic expressions)

Given, e.g. e class named SampleClass

//Create the class wrapper descriptor, this can be cached and reused!
var classWrapperDescriptor = new ClassWrapperDescriptor(typeof(SampleClass));
//Initialize the descriptor
classWrapperDescriptor.Load();

//Create the instance of our object
object instance = new SampleClass();

//Create an instance of the wrapper
var classWrapper = classWrapperDescriptor.CreateWrapper(instance);

//Set a property
classWrapper.Set("StringProperty","test");

//Get a property
var stringPropertyValue = classWrapper.Get<string>("StringProperty");

//Invoke a method without return statement
classWrapper.Invoke("ParamMethod", "paramValue");

//Invoke a method witho return statement
var result = classWrapper.Invoke<int>("ReturnMethod", "paramValue");

Any feedback on this library is really appreciated!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文