目次

概要

キャスト演算子と as 演算子の実行速度に関しての話を少々。

ちなみに、 キャストと as には以下のような差もあります。

  • as は変換なしで代入可能かどうかしか判定しない(ユーザ定義の型変換演算子は呼んでくれない)

  • as は参照型(class)にしか使えない

キャストと as の実行速度

普通のキャストと as は、ちゃんと型変換できるなら得られる結果は一緒で、失敗時には、

  • キャスト: InvalidCast 例外発生

  • as: null を返す

という違いがあります。 (例外に関しては、「例外処理」参照。)

C# の例外処理機構は、 try catch を書くだけならほとんどコストはないんですが、 例外が throw された場合にはかなり重たい負荷がかかります。 なので、型変換に失敗する可能性があるときは as にする方がほぼ確実にパフォーマンスがよくなります。

確実に型変換ができる場合

じゃあ、100%確実に型変換ができるとわかっている場合はどうでしょう。

ちなみに、キャスト演算子と as 演算子は、以下のような 「IL」 にコンパイルされます。

  • キャスト: castclass 命令

  • as: isinst 命令

IL 上はどちらも1命令で、 命令の差でパフォーマンスの違い推測できないんで、ここは実測してみます。 for ループの中でキャストか as するだけの関数を書いて、

Stopwatch sw = new Stopwatch();

sw.Reset();
sw.Start();
TestCast(N);
Console.Write("{0}\n", sw.ElapsedTicks);

sw.Reset();
sw.Start();
TestAs(N);
Console.Write("{0}\n", sw.ElapsedTicks);

として、時間を計ってみます。 結果、キャスト演算の方が1割程度高速でした。

(ちなみに、キャスト演算子を使って型変換に失敗した場合、 例外が発生するとパフォーマンスは2桁3桁余裕で悪化します。)

as と is の実行速度

確実に型変換できる場合にキャストの方が早いなら、 以下のようなコードを書けば実行速度が速くなるかというと、 そんなことはない。

B b = new D(); // D extends B

if (b is D)
{
  D d = (D)b;
}

なぜかというと、is は、内部的には as とまったく同じコードになるから。 以下のような2つのコードがほぼ同じコンパイル結果になります。

B b = new D(); // D extends B
D d = b as D;
if (d != null)
  ...
B b = new D(); // D extends B
if (b is D)
  ...

要するに、is 演算子は as + null 比較相当のコードになります。 その結果、「isで型を調べてからキャスト」は単に2度手間なだけで、遅くなります。

更新履歴

test

[雑記]

ブログ