kazumalab tech log

流行りとリラックマと嵐が大好きです。技術的ログ。

UnityのResourcesからLoadする際のキャストの件

かずまです。

UnityでResourcesからLoadするときになにもキャストしない場合Object型で返ってきます。
ただそれではGameObjectとして使えないのでキャストする必要があります。
今回はas演算子もキャストとして扱っています。
どの方法が一番はやく処理ができるのか、気になったので今回はそれを計測してメモしておきたいと思います。

キャスト方法

現在僕が知っている限りResourcesからのGameObjectへの型の変換方法は3つです。

asを使う

GameObject obj = Resources.Load ("Prefabs/Box/Wood") as GameObject;

予想ではasは早いと聞いたのでこれが早いかと!

(GameObject) 対象物

GameObject obj = (GameObject) Resources.Load ("Prefabs/Box/Wood");

これだとInvalidCastExceptionが投げられる場合があるので2つめの引数として型を指定します。

(GameObject)対象物 + typeof(GameObject)

GameObject obj = (GameObject) Resources.Load ("Prefabs/Box/Wood", typeof(GameObject));

二段階で念入りではありますが、これ実は2回も型変換しているので遅いのでは?と思っています。

Genericで指定

GameObject obj = Resources.Load<GameObject> ("Prefabs/Box/Wood");

Genericはコードを書く文にはキャストし忘れ、ということは減るはずなのでいいのですが、はたしてas演算子とどう変わるかといったところですね。

速度計測方法

今回は上記コードを1万回Loadし、そのたびに速度(時間)を計測します。
それを100回試行し、平均を取ります。

計測に使うのは
C#のStopwatchです。
Stopwatch クラス (System.Diagnostics)

プログラムのサンプルはこちら。

// asでの型変換の計測
for(int count = 0; count < times; count++) {
			Stopwatch st = new Stopwatch ();
			st.Start ();
			for (int i = 0; i < 10000; i++) {
				GameObject obj = Resources.Load ("Prefabs/Box/Wood") as GameObject;
			}
			st.Stop ();
			total_as += st.Elapsed.TotalMilliseconds;
}

PCの性能

OS : macOS Sierra 10.12.2
CPU : 2.9 GHz Intel Core i5
メモリ : 8 GB 2133 MHz

Unityと.Net Framework

Unity 5.5.0f3 Personal (64bit)
.NET Framework 4.5

こんな感じです。

計測結果

以下の結果になりました。
f:id:kazumalab:20170115015326p:plain

表に早い順番に並べるとこのような感じ。

方法 実行時間(100回平均)
as演算子 9.47781ms
(GameObject)対象物 + typeof 9.74216ms
(GameObject)対象物 9.99564ms
Generic 10.02538ms

予想ではas演算子が早いということでしたが、ほんとに早かったです。
as演算子を使う場合は少し制約があるのでそこも考えないと行けないです。

nullが返ってくる

キャストが出来なかった場合、InvalidCastExceptionをthrowされますが、
as演算子ではnullが返ってきます。

ufcpp.net

予想より早い(GameObject)対象物 + typeof(GameObject)

今回は早い結果となりましたが、何回か再生をポチポチした時にtypeofがない方が早いという結果になることも。
一概には早かったとはいえないけど、そこまで遅くないので使うのは良さそうですね。

Genericでは他に比べると遅いのかな、という印象でした。
高速に使うならas演算子、確実にキャストするなら(GameObject)対象物 + typeof(GameObject)を使うのが良さそうですね。

もし、もっとこうしたほうが良い、ホントはこうだと思うことがあればどんどんコメントでください。
絶賛C#マスター中ですのでご指摘、議論は嬉しいです。

よろしくお願いします。