想象一下,我们有一个可变结构(是的,不启动):
公共结构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 _ * 似乎工作。 其实,这主要是拆箱(见历史版本与 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德尔=(动作<对象,INT>)dynMtd.CreateDelegate(typeof运算(动作<对象,INT>)); 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 }
更多推荐
如何使用变异IL盒装结构
发布评论