C#反思 - 如何设置结构域的值 [英] C# Reflection - How to set field value for struct
问题描述
如何使用DynamicMethod使用反射将值设置为struct字段 - myStruct.myField
?当我调用 setter(myStruct,111)
值未设置时,因为 MyStruct
是值类型。 Console.WriteLine(myStruct.myField)
显示值3.
answer如何修改 GetDelegate
方法将值设置为 myStruct.myField
?
How can I set value into struct field - myStruct.myField
with reflection using DynamicMethod? When I call setter(myStruct, 111)
value was not set, because MyStruct
is value type. Console.WriteLine(myStruct.myField)
shows value 3.
How to modify GetDelegate
method to set value into myStruct.myField
?
public struct MyStruct
{
public int myField;
}
public delegate void SetHandler(object source, object value);
private static SetHandler GetDelegate(Type type, FieldInfo fieldInfo)
{
DynamicMethod dm = new DynamicMethod("setter", typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
ILGenerator setGenerator = dm.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.DeclareLocal(type);
setGenerator.Emit(OpCodes.Unbox_Any, type);
setGenerator.Emit(OpCodes.Stloc_0);
setGenerator.Emit(OpCodes.Ldloca_S, 0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
setGenerator.Emit(OpCodes.Stfld, fieldInfo);
setGenerator.Emit(OpCodes.Ldloc, 0);
setGenerator.Emit(OpCodes.Box, type);
setGenerator.Emit(OpCodes.Ret);
return (SetHandler)dm.CreateDelegate(typeof(SetHandler));
}
MyStruct myStruct = new MyStruct();
myStruct.myField = 3;
FieldInfo fi = typeof(MyStruct).GetField("myField", BindingFlags.Public | BindingFlags.Instance);
SetHandler setter = GetDelegate(typeof(MyStruct), fi);
setter(myStruct, 111);
Console.WriteLine(myStruct.myField);
推荐答案
编辑:我犯了这个错误 - 有趣的事实; unbox-any返回值;
I made this mistake again - fun fact; unbox-any returns the value; unbox returns the pointer to the data - which allows in-place mutate.
这是工作的IL生成:
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Unbox, type);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
setGenerator.Emit(OpCodes.Stfld, fieldInfo);
setGenerator.Emit(OpCodes.Ret);
但是!这是一个盒装的副本;你需要之后unbox:
But! This is mutating a boxed copy; you would need to unbox afterwards:
object obj = myStruct;
setter(obj, 111);
MyStruct andBackAgain = (MyStruct)obj;
Console.WriteLine(andBackAgain.myField);
Console.WriteLine(myStruct.myField);
要做到这一点,你可能需要一个 ref MyStruct
,或者返回 MyStruct
。您可以返回包装的副本,但这不会使它更容易使用。坦率地说,它是哑巴:结构一般不应该是可变的。
To do it in place, you would probably need the method to take a ref MyStruct
, or to return a MyStruct
. You could return the boxed copy, but that doesn't make it much easier to use. Frankly, it is moot: structs should not generally be mutable.
这篇关于C#反思 - 如何设置结构域的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!