如何使用变异IL盒装结构如何使用、结构、IL

2023-09-04 01:35:46 作者:萱草

想象一下,我们有一个可变结构(是的,不启动):

 公共结构MutableStruct
{
    公众诠释富{获得;组; }
    公共重写字符串的ToString()
    {
        返回Foo.ToString();
    }
}
 

使用反射,我们可以利用这个被包装实例结构和其变异箱子里面:

  //这基本上就是我们要效仿
obj对象=新MutableStruct {美孚= 123};
。obj.GetType()的getProperty(富)的SetValue(OBJ,456)。
的System.Console.WriteLine(OBJ); //456
 

我会的喜欢的要做的就是写一些白细胞介素,可以做与此相同 - 但速度更快。我是一个元编程迷; P

这是微不足道的拆箱,任何的价值和使用常规白细胞介素变异的价值 - 但你不能只是叫事后箱,因为这将创建一个不同的框。我的猜测的是什么,我们需要做的,是复制它在现有的框。我已经调查 ldobj / stobj ,但这些似乎并没有做的工作(除非我失去了一些东西)。

所以:做一个机制来做到这一点存在吗?或者,我必须限制自己的反射进行就地更新盒装结构 S'

或者换句话说:什么? ...邪在这儿... ...

  VAR方法=新的DynamicMethod的(神雕侠侣,空,
    新的[] {typeof运算(对象)的typeof(对象)});
变种IL = method.GetILGenerator();
// ...邪在这儿... ...
il.Emit(欧普codes.Ret);

动作<对象,对象>行动=(动作<对象,对象>)
    method.CreateDelegate(typeof运算(动作<对象,对象>));
行动(OBJ,789);
的System.Console.WriteLine(OBJ); //789
 
基于全基因组测序数据鉴定结构变异的四大类方法总结

解决方案

嗯,这很有意思。

使用 Ldflda Stind _ * 似乎工作。 其实,这主要是拆箱(见< A HREF =htt​​p://stackoverflow.com/revisions/18938444/2>历史版本与 Ldflda作品 Stind _ * )。

下面是我砍死在一起 LinqPad 来证明这一点了。

 公共结构MutableStruct
{
    公众诠释富{获得;组; }

    公共重写字符串的ToString()
    {
        返回Foo.ToString();
    }
}

无效的主要()
{
    无功富= typeof运算(MutableStruct).GetProperty(富);
    VAR setFoo = foo.SetMethod;

    VAR dynMtd =新的DynamicMethod的(恶的typeof(无效),新的[] {typeof运算(对象)的typeof(INT)});
    变种IL = dynMtd.GetILGenerator();
    il.Emit(欧普codes.Ldarg_0); // 目的
    il.Emit(欧普codes.Unbox的typeof(MutableStruct)); // MutableStruct和放大器;
    il.Emit(欧普codes.Ldarg_1); // MutableStruct和放大器; INT
    il.Emit(欧普codes.Call,setFoo); // --empty--
    il.Emit(欧普codes.Ret); // --empty--

    VAR德尔=(动作&LT;对象,INT&GT;)dynMtd.CreateDelegate(typeof运算(动作&LT;对象,INT&GT;));

    VAR MUT =新MutableStruct {美孚= 123};

    VAR盒装=(对象)MUT;

    德尔(盒装,456);

    VAR拆箱=(MutableStruct)盒装;
    // unboxed.Foo = 456,mut.Foo = 123
}
 

Imagine we have a mutable struct (yes, don't start):

public struct MutableStruct
{
    public int Foo { get; set; }
    public override string ToString()
    {
        return Foo.ToString();
    }
}

Using reflection, we can take a boxed instance of this struct and mutate it inside the box:

// this is basically what we want to emulate
object obj = new MutableStruct { Foo = 123 };
obj.GetType().GetProperty("Foo").SetValue(obj, 456);
System.Console.WriteLine(obj); // "456"

What I would like to do is to write some IL that can do the same as this - but faster. I'm a meta-programming junkie ;p

It is trivial to unbox-any the value and mutate the value using regular IL - but you can't just call box it afterwards because that will create a different box. I'm guessing that what we would need to do here is copy it over the existing box. I have investigated ldobj / stobj, but those don't seem to do the job (unless I'm missing something).

So: does a mechanism to do this exist? Or must I limit myself to reflection to perform in-place updates of boxed structs ?

Or in other words: what ... evil goes here... ?

var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(object) });
var il = method.GetILGenerator();
// ... evil goes here...
il.Emit(OpCodes.Ret);

Action<object, object> action = (Action<object, object>)
    method.CreateDelegate(typeof(Action<object, object>));
action(obj, 789);
System.Console.WriteLine(obj); // "789"

解决方案

Well, that was fun.

Using Ldflda and Stind_* seems to work. Actually, it's mostly Unbox (see history for version that works with Ldflda and Stind_*).

Here's what I hacked together in LinqPad to prove it out.

public struct MutableStruct
{
    public int Foo { get; set; }

    public override string ToString()
    {
        return Foo.ToString();
    }
}

void Main()
{
    var foo = typeof(MutableStruct).GetProperty("Foo");
    var setFoo = foo.SetMethod;

    var dynMtd = new DynamicMethod("Evil", typeof(void), new [] { typeof(object), typeof(int) });
    var il = dynMtd.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);                       // object
    il.Emit(OpCodes.Unbox, typeof(MutableStruct));  // MutableStruct&
    il.Emit(OpCodes.Ldarg_1);                       // MutableStruct& int
    il.Emit(OpCodes.Call, setFoo);                  // --empty--
    il.Emit(OpCodes.Ret);                           // --empty--

    var del = (Action<object, int>)dynMtd.CreateDelegate(typeof(Action<object, int>));

    var mut = new MutableStruct { Foo = 123 };

    var boxed= (object)mut;

    del(boxed, 456);

    var unboxed = (MutableStruct)boxed;
    // unboxed.Foo = 456, mut.Foo = 123
}