如何使用 DynamicMethod 通过反射将值设置为 struct 字段 - myStruct.myField
?当我调用 setter(myStruct, 111)
时没有设置值,因为 MyStruct
是值类型。 Console.WriteLine(myStruct.myField)
显示值为 3。
如何修改 GetDelegate
方法将值设置为 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);
最佳答案
编辑:I made this mistake again - 有趣的事实; unbox-any 返回值; unbox 返回指向数据的指针 - 这允许就地变异。
这是工作的 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);
但!这是对盒装副本进行变异;之后您需要拆箱:
object obj = myStruct;
setter(obj, 111);
MyStruct andBackAgain = (MyStruct)obj;
Console.WriteLine(andBackAgain.myField);
Console.WriteLine(myStruct.myField);
要做到这一点,您可能需要使用
ref MyStruct
或返回 MyStruct
的方法。您可以退回盒装副本,但这并不会使其更易于使用。坦率地说,这是没有实际意义的:结构通常不应该是可变的。关于C# 反射 - 如何为结构设置字段值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25631322/