[Unity]IL2CPP(AOT)+Generic+Reflectionの罠

IL2CPPの事前コンパイル(AOT: Ahead-of-time)環境でジェネリッククラスやジェネリックメソッドをReflection(MakeGenericType/MakeGenericMethod)経由で使おうとするとExecutionEngineExceptionという例外が発生する場合がある。

事前コンパイルについてのUnityマニュアルはこちら: https://docs.unity3d.com/ja/current/Manual/ScriptingRestrictions.html

例えば以下のようなコードがあったとする。

// どこぞのメソッド内
var type = typeof(List<>).MakeGenericType(typeof(TestStruct)); // 他のコード上ではList<TestStruct>を直接使ってない。
var instance = System.Activator.CreateInstance(type);
type.InvokeMember("Add", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, instance, new object[] { new TestStruct() }); // ここでExecutionEngineException

Debug.Log(((IList<TestStruct>)instance)[0].ToString());

※InspectorウィンドウでTestStruct型を指定して、コード上ではそれが何なのか意識したくない場合に使うような想定

で、なぜこれで例外が発生するかというと

  • IL2CPPはその名の通り、IL(.NET用の中間コード)をC++へ変換する。
  • List<なんちゃら>をReflectionからのみ使用すると、事前にC++へ変換するときに「存在しないもの」なので未実装になる。
  • 実行時にReflection経由で呼び出そうとすると「未実装なので実行できないよ」っと例外発生。

という感じ。

なので、以下のようにコンパイラーに存在を認識させれば動作するようになる。

// どこぞの型の中
public List<TestStruct> imhere = new List<TestStruct>();

この変数はコンパイラーが存在を認識して中身を実装さえしてくれれば良いので、宣言するだけしておけばOK

Unityのアセット販売中!

ステートマシンの状態遷移やパラメータはエディタで編集でき、
ゲームロジックに依存するステートの挙動はスクリプトで記述可能なエディタ拡張。

詳細はこちら

RPGツクールVXやWOLF RPGエディターのオートタイルに準拠したエディタ拡張。

詳細はこちら

オススメ!