创建 DynamicMethod 来为属性赋值?

发布于 2024-10-10 19:15:52 字数 2493 浏览 3 评论 0原文

这是一个学习练习。我创建了一个方法,它接受 Foo 和一个字符串并设置 A 属性。我使用 Reflector 反汇编来发出以下代码。反汇编看起来像这样:

.method private hidebysig static void Spork(class ConsoleTesting.Foo f, string 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: callvirt instance void ConsoleTesting.Foo::set_A(string)
    L_0007: ret 
}

好的,所以我在那之后建模了我的发出代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;


namespace ConsoleTesting
{
    class Foo
    {
        public string A { get; set; }
    }

    class Program
    {
        static Action<Foo, string> GenMethodAssignment(string propName)
        {
            MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
            if (setMethod == null)
                throw new InvalidOperationException("no property setter available");

            Type[] argTypes = new Type[] { typeof(Foo), typeof(String) };
            DynamicMethod method = new DynamicMethod("__dynamicMethod_Set_" + propName, null, argTypes, typeof(Program));
            ILGenerator IL = method.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Callvirt, setMethod);
            IL.Emit(OpCodes.Ret);
            method.DefineParameter(1, ParameterAttributes.In, "instance");
            method.DefineParameter(2, ParameterAttributes.In, "value");

            Action<Foo, string> retval = (Action<Foo, string>)method.CreateDelegate(typeof(Action<Foo, string>));
            return retval;
        }

        static void Main(string[] args)
        {
            Foo f = new Foo();
            var meth = GenMethodAssignment("A");
            meth(f, "jason");
            Console.ReadLine();
        }
    }

我得到了这个异常:

JIT Compiler encountered an internal limitation.

这是什么意思,我该如何修复它?

编辑:

我想可能是因为目标方法是私有的,但我不太确定。来自 DynamicMethod MSDN 页面< /a>:

以下代码示例创建一个与类型逻辑关联的 DynamicMethod。该关联使其能够访问该类型的私有成员。

This is a learning exercise. I created a method that takes a Foo and a string and sets the A property. I used the Reflector disassembly to make the following emit code. The disassembly looks like this:

.method private hidebysig static void Spork(class ConsoleTesting.Foo f, string 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: callvirt instance void ConsoleTesting.Foo::set_A(string)
    L_0007: ret 
}

Ok, so I modeled my emit code after that:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;


namespace ConsoleTesting
{
    class Foo
    {
        public string A { get; set; }
    }

    class Program
    {
        static Action<Foo, string> GenMethodAssignment(string propName)
        {
            MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
            if (setMethod == null)
                throw new InvalidOperationException("no property setter available");

            Type[] argTypes = new Type[] { typeof(Foo), typeof(String) };
            DynamicMethod method = new DynamicMethod("__dynamicMethod_Set_" + propName, null, argTypes, typeof(Program));
            ILGenerator IL = method.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Callvirt, setMethod);
            IL.Emit(OpCodes.Ret);
            method.DefineParameter(1, ParameterAttributes.In, "instance");
            method.DefineParameter(2, ParameterAttributes.In, "value");

            Action<Foo, string> retval = (Action<Foo, string>)method.CreateDelegate(typeof(Action<Foo, string>));
            return retval;
        }

        static void Main(string[] args)
        {
            Foo f = new Foo();
            var meth = GenMethodAssignment("A");
            meth(f, "jason");
            Console.ReadLine();
        }
    }

I'm getting this exception:

JIT Compiler encountered an internal limitation.

What the krunk does that mean, and how do I fix it?

EDIT:

I thought maybe it's because the target method is private, but I'm not so sure. From the DynamicMethod MSDN page:

The following code example creates a DynamicMethod that is logically associated with a type. This association gives it access to the private members of that type.

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

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

发布评论

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

评论(3

还在原地等你 2024-10-17 19:15:52

有趣的问题。首先,您可以做几件事。如果您只需要 setter 的委托,则可以使用 Delegate.CreateDelegate

Delegate.CreateDelegate(typeof(Action<Foo, string>),typeof(Foo).GetProperty("A").GetSetMethod()) as Action<Foo,String>;

如果您使用 .NET 3.5+,则可以使用表达式树,我强烈建议通过 DynamicMethod 学习它们,它们在 .NET 3.5 中的使用有限,在 .NET 4 中几乎没有。(尽管 TypeBuilder 仍然非常有用)。

var targetExpression = Expression.Parameter(typeof(Foo),"target");
var valueExpression = Expression.Parameter(typeof(string),"value");
var expression = Expression.Lambda<Action<Foo,string>>(
      Expression.Call(
           targetExpression, 
           typeof(Foo).GetProperty("A").GetSetMethod(),
           valueExpression
      ),
      targetExpression,
      valueExpression
);

在 .NET 4 中,您可以使用 Expression.Assign 将其编写得稍微漂亮一些,但也好不了多少。

最后,如果你真的想在 IL 中做到这一点,这是可行的。

        DynamicMethod method = new DynamicMethod("Setter", typeof(void), new[] { typeof(Foo), typeof(string) }, true);
        var ilgen = method.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Ldarg_1);
        ilgen.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("A").GetSetMethod());
        ilgen.Emit(OpCodes.Ret);
        var action = method.CreateDelegate(typeof(Action<Foo,string>)) as Action<Foo,string>;

我认为你的问题是你当前调用的 set 方法实际上是 getMethod 错误就在这一行::
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);

我从未分配过参数属性,但这也可能是一个问题。

Interesting issue. First there are few things you can do. If you only want a delegate for the setter you can use Delegate.CreateDelegate.

Delegate.CreateDelegate(typeof(Action<Foo, string>),typeof(Foo).GetProperty("A").GetSetMethod()) as Action<Foo,String>;

If you are using .NET 3.5+ you can use expression trees and I strongly recommend learning them over DynamicMethod, they have limited use in .NET 3.5 and almost none .NET 4. (TypeBuilder is still very useful though).

var targetExpression = Expression.Parameter(typeof(Foo),"target");
var valueExpression = Expression.Parameter(typeof(string),"value");
var expression = Expression.Lambda<Action<Foo,string>>(
      Expression.Call(
           targetExpression, 
           typeof(Foo).GetProperty("A").GetSetMethod(),
           valueExpression
      ),
      targetExpression,
      valueExpression
);

In .NET 4 you can write it to be slightly prettier by using Expression.Assign, but it's not much better.

Finally, if you really want to do it in IL this works.

        DynamicMethod method = new DynamicMethod("Setter", typeof(void), new[] { typeof(Foo), typeof(string) }, true);
        var ilgen = method.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Ldarg_1);
        ilgen.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("A").GetSetMethod());
        ilgen.Emit(OpCodes.Ret);
        var action = method.CreateDelegate(typeof(Action<Foo,string>)) as Action<Foo,string>;

I think your issue is that you are currently calling the set method is actually the getMethod the error is on this line::
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);

I've never assigned parameter attributes but that may also be an issue too.

随波逐流 2024-10-17 19:15:52

好吧,我想通了。更改

IL.Emit(OpCodes.Callvirt, setMethod);

IL.Emit(OpCodes.Call, setMethod);

修复它。我不知道为什么反汇编显示 CallVirt,但是呃。

Well I figured it out. Changing

IL.Emit(OpCodes.Callvirt, setMethod);

to

IL.Emit(OpCodes.Call, setMethod);

fixed it. I don't know why the disassembly showed CallVirt, but eh.

不疑不惑不回忆 2024-10-17 19:15:52

这需要在什么版本的 .NET 上运行?从表达式树编译委托会容易得多。

What version of .NET does this need to run on? Compiling a delegate from an expression tree would be much easier.

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