C# 使用Reflection.Emit设置静态字段的值在Unity中失败
我正在尝试使用C# 使用Reflection.Emit设置静态字段的值在Unity中失败,c#,unity3d,reflection.emit,C#,Unity3d,Reflection.emit,我正在尝试使用Reflection.Emit设置静态字段的值(我无法访问.NET 4的表达式.Assign,因为我一直使用Unity的.NET 3.5) 我目前的代码如下: public Action<TTarget, TField> GetSetter<TTarget, TField>(FieldInfo fieldInfo) { DynamicMethod setterMethod = new DynamicMethod ( "sett
Reflection.Emit
设置静态字段的值(我无法访问.NET 4的表达式.Assign
,因为我一直使用Unity的.NET 3.5)
我目前的代码如下:
public Action<TTarget, TField> GetSetter<TTarget, TField>(FieldInfo fieldInfo)
{
DynamicMethod setterMethod = new DynamicMethod
(
"setter",
typeof(void),
new Type[] { typeof(TTarget), typeof(TField) },
typeof(TTarget)
);
var setterIL = setterMethod.GetILGenerator();
if (fieldInfo.IsStatic)
{
setterIL.Emit(OpCodes.Ldnull);
}
else
{
setterIL.Emit(OpCodes.Ldarg_0);
}
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fieldInfo);
setterIL.Emit(OpCodes.Ret);
return (Action<TTarget, TField>)setterMethod.CreateDelegate(typeof(Action<TTarget, TField>));
}
改为使用(设置静态字段):
NET运行时在幕后可能比Mono运行时更宽松(即:它允许
Stfld
,即使是静态字段,只忽略第一个参数,而Mono不允许),这就解释了为什么问题只发生在Unity中。您确定这就是确切的代码吗GetSetter
不应编译-不能将静态类型用作类型参数。此外,不需要检查字段是否为静态。由于您的方法要求目标(并且您提供了它:Invoke(null,123)
),因此您应该始终发出Ldarg\u 0
。这也会导致有人编写Invoke(notnullinstance,123)
,这会引发一个错误,但会悄悄地将123
设置为静态字段。没错,这个类不是静态的,我匆忙地给出了一个简化的示例。根据,您又是对的,Ldarg_0
应该可以工作,但它不工作。在这种情况下,我无法复制它(复制并粘贴代码而不进行更改),它工作得很好。您正在运行哪个框架版本?你确定这个字段确实是静态的吗?我只是复制并粘贴了我提供的示例代码,然后得到了错误。我在Unity内部使用.NET3.5。
using System;
using System.Reflection;
using System.Reflection.Emit;
using UnityEditor;
class Program
{
public static Action<TTarget, TField> GetSetter<TTarget, TField>(FieldInfo fieldInfo)
{
DynamicMethod setterMethod = new DynamicMethod
(
"setter",
typeof(void),
new Type[] { typeof(TTarget), typeof(TField) },
typeof(TTarget)
);
var setterIL = setterMethod.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fieldInfo);
setterIL.Emit(OpCodes.Ret);
return (Action<TTarget, TField>)setterMethod.CreateDelegate(typeof(Action<TTarget, TField>));
}
public class Static
{
public static int x;
}
[MenuItem("Tools/Debug IL")]
static void Debug()
{
var fieldInfo = typeof(Static).GetField("x");
var setter = GetSetter<Static, int>(fieldInfo);
setter.Invoke(null, 123);
Debug.Log("Static field assignment succeeded.");
}
}
using System;
using System.Reflection;
using System.Reflection.Emit;
using UnityEditor;
class Program
{
public static Action<TTarget, TField> GetSetter<TTarget, TField>(FieldInfo fieldInfo)
{
DynamicMethod setterMethod = new DynamicMethod
(
"setter",
typeof(void),
new Type[] { typeof(TTarget), typeof(TField) },
typeof(TTarget)
);
var setterIL = setterMethod.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fieldInfo);
setterIL.Emit(OpCodes.Ret);
return (Action<TTarget, TField>)setterMethod.CreateDelegate(typeof(Action<TTarget, TField>));
}
public class Static
{
public static int x;
}
[MenuItem("Tools/Debug IL")]
static void Debug()
{
var fieldInfo = typeof(Static).GetField("x");
var setter = GetSetter<Static, int>(fieldInfo);
setter.Invoke(null, 123);
Debug.Log("Static field assignment succeeded.");
}
}
if (fieldInfo.IsStatic)
{
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Stsfld, fieldInfo);
setterIL.Emit(OpCodes.Ret);
}
else
{
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fieldInfo);
setterIL.Emit(OpCodes.Ret);
}