Reflection.Emit
を使用して静的フィールドの値を設定しようとしています(.NET 4のExpression.Assign
にアクセスできない.NET 3.5)。次のようにUnityでReflect.Emitを使用して静的フィールドの値を設定すると、エラーが発生する
私の現在のコードは次のとおりです。
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>));
}
そして、私が使用して設定メソッドの呼び出し:
public class Static
{
public static int x;
}
var fieldInfo = typeof(Static).GetField("x");
var setter = GetSetter<Static, int>(fieldInfo);
setter.Invoke(null, 123);
私は、このエラーメッセージが出ます:
とNullReferenceException:オブジェクト参照をオブジェクトのインスタンスに設定されていません (ラッパー動的メソッド)setter(...、int)
最初の引数(Ldnull
オペコード)がnullを読み込んでいると思っても問題は解決しませんが、動作していないようです。私は間違って何をしていますか?
更新:コードがUnity(最新、5.5.0p4)内から実行されている場合にのみ例外が発生するようです。 Visual Studioから作成された.NET 3.5コンソールアプリケーションでは、問題はありません。 UnityのMonoコンパイラに問題がありますか?
Unityのメニュー項目Tools > Debug IL
からテストする完全なコードです。
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.");
}
}
正確なコードは本当ですか? 'GetSetter'はコンパイルすべきではありません。型引数として静的型を使うことはできません。 –
Rob
また、フィールドが静的であるかどうかを確認する必要もありません。あなたのメソッドはターゲットを尋ねるので( 'Invoke(null、123)')、 'Ldarg_0'を出すだけです。これはまた、誰かが 'Invoke(notnullinstance、123)'を書くときに問題を引き起こします。*これはエラーをスローするべきですが、静的フィールドに '123 'を静かに設定します。 – Rob
あなたはそうです、クラスは静的ではありません。私は急いで簡単な例をまとめます。 [MSDN](https://msdn.microsoft.com/en-us/library/aya2tw8f(v = vs.100).aspx)によれば、あなたはもう一度、Ldarg_0が動作するはずですが、 t。 – Lazlo