Ответ 1
Является ли компилятор преобразованием этого выражения в код, который обычно недействительным?
Когда я смотрел на спецификацию около часа, я начинаю убеждать себя, что это просто край, который был упущен в спецификации. Обратите внимание, что это всего лишь способ для композиторов языка С# выразить оператор as
с семантикой оператора is
.
Компилятор фактически не конвертирует оператор as
в тернарный оператор с is
. Он выдает вызов IL на isinst
, как для 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 динамичен, почему сначала он бросает E в объект, тогда T в то время как (T) E вполне справедливо?
Это описано в мелкой печати спецификации:
Если тип времени компиляции E является динамическим, , в отличие от оператора трансляции оператор as не динамически связан (§7.2.2). Следовательно расширение в этом случае:
E is T ? (T)(object)(E) : (T)null
Приведение в 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, он объясняет, что на самом деле семантика представления от оператора "как оператор" до "оператора трансляции" пытается выполнить:
Я согласен, в спецификации тоже есть неточный язык. Он говорит, что оператор "как" всегда применим, если задействован открытый тип, но затем описывает его оценку с точки зрения приведения, что может быть недействительным в некоторых случаях. Он должен сказать, что отливки в расширении не представляют собой обычный оператор С# cast, а просто представляют преобразования, которые разрешены в операциях "как".. Я сделаю заметку, чтобы исправить это. Спасибо!