dynamicキーワードを使って変数やメソッドを動的に操作する方法です。
Unity2018.3.6f1
Scripting Runtime Version : .Net 4.x Equivalent
Api Comptibility Level : .Net 4.x
iOSのIL2CPPビルドではまだ使えない
dynamicは内部的にExpression Treeを使っています。
そしてExpression TreeはiOS + IL2CPPでビルドするとランタイムエラーになります(本記事作成時点では)。
これについては次の記事を参照してください。
エディタ拡張ではもちろん使えます。
dynamic?
dynamicはC#4.0から追加されたキーワードで、変数やメソッドに動的に(文字列で)アクセスできます。
要するに、こんなことができます。
// 適当にMonoBehaviourを取得(何でもいい) MonoBehaviour behaviour = GetComponent<MonoBehaviour>(); // MonoBehaviourをdynamicな変数に格納する dynamic dynamicBehaviour = behaviour; // MonoBehaviourに定義されていない任意の名前のメソッドを呼べる // (普通はコンパイルエラーになる) dynamicBehaviour.SomeMethod();
上記のコードは、GetComponent()
したMonoBehaviour
のサブクラスにSomeMethod()
が定義されていれば、正常にそのメソッドが呼ばれます。
dynamicを使わないでこれを実現する場合はリフレクションやExpression Treeを使う必要がありました。
dynamicはこれらの代替手段と言えそうです。
ちなみにdynamicは内部的にはExpression Treeを使っているとのことです。
Expression Treeと同じ程度(ちょい悪いくらい)のパフォーマンスで、Expression Treeよりもずっと簡潔に書けるためメリットは大きそうです。
もちろんリフレクションよりはずっとパフォーマンスが良いです。
Unityとdynamic
さてUnityでdynamicを使うには、Scripting Runtime Versionを.Net 4.x Equivalent
にする必要があります。
この設定によりdynamicを使ったソースコードを記述できるようになります。
ただし、Unity2018.3.6ではコンパイル時に下記のエラーが出てしまいました。
error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'
これを解決するにはApi Compatibility Level
を.Net 4.x`に上げる必要があります。
これでコンパイルエラーも出なくなりました。
Reflectionの代わりに使う
それでは実際にdynamicキーワードを使ってみます。
古いバージョンではReflectionを使わないと実現できなかったようなケースをdynamicで実現してみます。
using UnityEngine; public class DynamicExample : MonoBehaviour { [SerializeField] private MonoBehaviour _behaviour; private void Start() { dynamic example = _behaviour; // メソッド example.Example(); // フィールド Debug.Log(example.exampleField); // プロパティ Debug.Log(example.ExampleProp); } }
このSerializeFieldに下記のコンポーネントの参照を持たせます。
using UnityEngine; public class DynamicReceiver : MonoBehaviour { private int exampleField = 2; public float ExampleProp { get; set; } = 5.0f; public void Example() { Debug.Log("example"); } }
無事実行されることが確認できました。
ちなみに、変数やメソッドが定義されていない場合には例外が発生し、
さらに変数がメソッドがprivateでも例外が発生しました。
jsonやxmlへのアクセスも簡易的に書ける
またdynamicを使うとjsonやxmlの取り扱いが非常にシンプルで直観的に書けます。
Dictionary等を使って煩雑に書く必要も、JsonUtilityを使って型を定義する必要もありません。
ただ、System.Dynamic.DynamicObject
を継承したクラスを作る必要はあります。
このあたりは素晴らしいライブラリがあるようなのでリンクで済ませてしまいます。