キャストと as

2chがプロパイダ規制食らってて書けないからここにメモっとく。
キャストと as の速度の問題。
普通のキャストと as は、ちゃんと型変換できるなら得られる結果は一緒で、失敗時には、

  • キャスト: 例外発生
  • as: null を返す

で、例外の throw ってのはかなり重たい処理で、型変換に失敗する可能性があるときは as にする方が大体パフォーマンスがいい。

じゃあ、100%型変換できるとわかってる場合はどう?という話に。
IL Disasem して調べてみると、単に、命令が1個違うだけだった↓。

  • キャスト: castclass 命令
  • as: isinst 命令

命令の差でパフォーマンスの違い推測できないんで、ここは実測。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割程度速い

まあ、100%キャストできることがわかってるケースなんて、大半は generics 使えばキャスト不要になりそうな気がしなくもない。

その他細々

ちなみに、型変換できなかった場合のコストは

  • as: if(obj != null) を追加しても処理が倍程度に増えるだけ
  • キャスト: 例外が発生すると 2ケタ・3ケタ遅い

あと、as と is の関係、

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)
  ...

がほとんど同じコードになってた。
IL の isinst 命令は C# の as 相当の命令で、is の方は isinst + null 比較(as + if文)になるっぽい。