as
これが非常に自然な使用例であることを考えると (実際に何をするかわからない場合)、
if (x is Bar) {
Bar y = x as Bar;
something();
}
は実質的に同等です (つまり、上記のコードからコンパイラによって生成されたCILは同等になります)。
Bar y = x as Bar;
if (y != null) {
y = x as Bar; //The conversion is done twice!
something();
}
編集:
私は自分の質問を明確にしていなかったと思います。もちろん冗長なので、2番目のスニペットを書くことはありません。最初のスニペットをコンパイルするときにコンパイラによって生成された CIL は、冗長な 2 番目のスニペットと同等であると主張しています。質問: a) これは正しいですか? b) もしそうなら、なぜそのようにis
実装されているのですか?
これは、最初のスニペットが実際によく書かれたものよりもはるかに明確できれいだと思うためです。
Bar y = x as Bar;
if (y != null) {
something();
}
結論:
is
/ケースの最適化はas
コンパイラの責任ではなく、JIT の責任です。
is
また、null チェックと同様に、両方の選択肢 (およびas
および) よりも少ない (is
そして安価な) 命令しかありませんcast
。
補遺:
CIL for as with nullcheck (.NET 3.5):
L_0001: ldarg.1
L_0002: isinst string
L_0007: stloc.0
L_0008: ldloc.0
L_0009: ldnull
L_000a: ceq
L_000c: stloc.1
L_000d: ldloc.1
L_000e: brtrue.s L_0019
L_0011: ldarg.0
L_0019: ret
is とキャストの CIL (.NET 3.5):
L_0001: ldarg.1
L_0002: isinst string
L_0007: ldnull
L_0008: cgt.un
L_000a: ldc.i4.0
L_000b: ceq
L_000d: stloc.1
L_000e: ldloc.1
L_000f: brtrue.s L_0021
L_0012: ldarg.1
L_0013: castclass string
L_0018: stloc.0
L_0019: ldarg.0
L_0021: ret
CIL for is and as (.NET 3.5):
L_0001: ldarg.1
L_0002: isinst string
L_0007: ldnull
L_0008: cgt.un
L_000a: ldc.i4.0
L_000b: ceq
L_000d: stloc.1
L_000e: ldloc.1
L_000f: brtrue.s L_0021
L_0012: ldarg.1
L_0013: isinst string
L_0018: stloc.0
L_0019: ldarg.0
L_0021: ret
これらは簡潔にするために編集されています (メソッド宣言、nops、something() の呼び出しは削除されています)。