コンパイラは、この式を通常は無効なコードに変換していますか?
約 1 時間仕様を見つめた後、これは単に仕様で見落とされていた特殊なケースであると確信し始めています。as
これは、C# 言語のコンポーザが演算子のセマンティクスを使用して演算子を表現するための単なる方法であることに注意してくださいis
。
コンパイラは実際as
には、演算子を . を使用して三項演算子に変換しませんis
。isinst
との両方に対してIL 呼び出しを発行しas
ますis
。
IL_0000: nop
IL_0001: ldstr "foo"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: isinst class ConsoleApplication2.Foo`1<!T>
IL_000d: stloc.1
IL_000e: ret
コンパイルされた DLL を見ると、as
オペレーターは手付かずのままです。
E の型が動的な場合、(T)E が完全に有効であるのに、最初に E をオブジェクトにキャストし、次に T をキャストするのはなぜですか?
これは、仕様の詳細に記載されています。
E のコンパイル時の型が動的である場合、キャスト演算子とは異なり、 as 演算子は動的にバインドされません(§7.2.2)。したがって、この場合の展開は次のようになります。
E is T ? (T)(object)(E) : (T)null
オブジェクトでを使用できるようにするには、 toへのキャストobject
が必要です。はコンパイル時の操作ですが、オブジェクトは実行時にのみバインドされます。as
dynamic
as
dynamic
コンパイラは、実際にはdynamic
型オブジェクトを最初から型としてobject
扱います。
class Foo<T>
{
public void SomeMethod()
{
dynamic str = "foo";
Foo<T> f = str as Foo<T>;
}
}
str
実際には、最初から次のように扱われobject
ます。
.class private auto ansi beforefieldinit Foo`1<T>
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig
instance void SomeMethod () cil managed
{
// Method begins at RVA 0x2050
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] object,
[1] class Foo`1<!T>
)
IL_0000: nop
IL_0001: ldstr "foo"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: isinst class Foo`1<!T>
IL_000d: stloc.1
IL_000e: ret
} // end of method Foo`1::SomeMethod
}
編集:
Managed Languages Team の Vladimir Reshetnikov と話をした後、彼は "as operator" から "cast operator" への表現のセマンティックが実際に何を伝えようとしているのかを説明しています。
同意します。仕様にも不正確な表現があります。オープンタイプが含まれる場合、「as」演算子は常に適用可能であると述べていますが、キャストの観点からその評価を説明しているため、場合によっては有効ではない可能性があります。展開内のキャストは、通常の C# キャスト演算子を表すのではなく、'as' 演算子で許可されている変換を表すだけであると言う必要があります。修正するのでメモしておきます。ありがとう!