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
E
is notdynamic
, the operationE as T
produces the same result asE is T ? (T)(E) : (T)null
If the compile-time type of
E
isdynamic
, unlike the cast operator theas operator
is 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
E
is dynamic why first it castsE
toobject
thenT
while the(T)E
is 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
as
operator with the semantics of theis
operator.The compiler doesn't actually convert the
as
operator to a ternary operator with anis
. It will emit an IL call toisinst
, both foras
andis
:Looking at the compiled DLL, the
as
operator remains untouched.This is described in the fine-print of the specification:
The cast to
object
is needed to make the use ofas
possible withdynamic
objects.as
is a compile-time operation whiledynamic
objects are bound only at run-time.The compiler actually treats
dynamic
type objects as typeobject
to begin with:str
is actually treated asobject
to 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: