I have just posted an answer to this question but I'm not entirely convinced of my answer.There are two things I'm wondering, consider this code:
class Foo<T>
{
void SomeMethod()
{
string str = "foo";
Foo<T> f = str as Foo<T>;
}
}
According to C# Specification 5.0, there are two different kinds of conversion of as operator.
If the compile-time type of
Eis notdynamic, the operationE as Tproduces the same result asE is T ? (T)(E) : (T)nullIf the compile-time type of
Eisdynamic, unlike the cast operator theas operatoris not dynamically bound (§7.2.2). Therefore the expansion in this case is:E is T ? (T)(object)(E) : (T)null
Since, this is invalid because of (Foo<T>)str
str is Foo<T> ? (Foo<T>)str : (Foo<T>)null;
I thought it should be translated as:
str is Foo<T> ? (Foo<T>)(object)str : (Foo<T>)null;
But the spec says this only happens when the type of E is dynamic.
So my questions are:
- Is the compiler translating this expression to a code that is normally invalid?
- When the type of
Eis dynamic why first it castsEtoobjectthenTwhile the(T)Eis completely valid?
After staring at the spec for about an hour, I'm starting to convince myself that this is simply an edge-case which was overlooked in the specification. Note that this is merely a way for the C# language composers to express the
asoperator with the semantics of theisoperator.The compiler doesn't actually convert the
asoperator to a ternary operator with anis. It will emit an IL call toisinst, both forasandis:Looking at the compiled DLL, the
asoperator remains untouched.This is described in the fine-print of the specification:
The cast to
objectis needed to make the use ofaspossible withdynamicobjects.asis a compile-time operation whiledynamicobjects are bound only at run-time.The compiler actually treats
dynamictype objects as typeobjectto begin with:stris actually treated asobjectto begin with:Edit:
After talking to Vladimir Reshetnikov from the Managed Languages Team, he explains what the semantic of the representation from the "as operator" to "cast operator" actually tries to convay: