Mar*_*ell 26 .net c# metaprogramming ilgenerator
想象一下,我们有一个可变的struct(是的,不要开始):
public struct MutableStruct
{
public int Foo { get; set; }
public override string ToString()
{
return Foo.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
使用反射,我们可以获取一个盒装实例,struct并在框内变异:
// 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"
Run Code Online (Sandbox Code Playgroud)
我会喜欢做的是写一些IL可以做同样的,因为这-但速度更快.我是一个元编程迷; p
拆箱 - 任何值并使用常规IL改变值是微不足道的 - 但是你不能只是在之后调用它,因为这将创建一个不同的框.我猜我们需要做的是将它复制到现有的盒子上.我已经调查了ldobj/ stobj,但那些似乎没有做到这一点(除非我遗漏了什么).
那么:是否存在这样做的机制?或者我必须限制自己反思以执行盒装structs 的就地更新?
换句话说:什么... 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"
Run Code Online (Sandbox Code Playgroud)
Kev*_*ose 18
嗯,这很有趣.
使用
实际上,它主要的Unbox(见的版本,随着工作的历史Ldflda和Stind_*似乎工作.Ldflda和Stind_*).
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
}
Run Code Online (Sandbox Code Playgroud)
干得好:
只是用unsafe:)
static void Main(string[] args)
{
object foo = new MutableStruct {Foo = 123};
Console.WriteLine(foo);
Bar(foo);
Console.WriteLine(foo);
}
static unsafe void Bar(object foo)
{
GCHandle h = GCHandle.Alloc(foo, GCHandleType.Pinned);
MutableStruct* fp = (MutableStruct*)(void*) h.AddrOfPinnedObject();
fp->Foo = 789;
}
Run Code Online (Sandbox Code Playgroud)
IL实现留给读者练习.
更新:
基于Kevin的回答,这是一个最小的工作示例:
ldarg.0
unbox MutableStruct
ldarg.1
call instance void MutableStruct::set_Foo(int32)
ret
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1119 次 |
| 最近记录: |