c# - try - ¿Cómo se traduce el operador "como" cuando el operando del lado derecho es genérico?
switch c# asp net (1)
¿El compilador está traduciendo esta expresión a un código que normalmente no es válido?
Después de observar la especificación durante aproximadamente una hora, empiezo a convencerme de que esto es simplemente un caso extremo que se pasó por alto en la especificación. Tenga en cuenta que esta es simplemente una forma para que los compositores en lenguaje C # expresen el operador as
con la semántica del operador is
.
El compilador no convierte realmente el operador as
a un operador ternario con un is
. isinst
una llamada IL a isinst
, tanto para as
y 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
En cuanto a la DLL compilada, el operador as
permanece intacto.
Cuando el tipo de E es dinámico, ¿por qué primero convierte E en objeto y luego T mientras que la (T) E es completamente válida?
Esto se describe en la letra pequeña de la especificación:
Si el tipo E de tiempo de compilación es dinámico, a diferencia del operador de conversión, el operador as no está enlazado dinámicamente (§7.2.2). Por lo tanto la expansión en este caso es:
E is T ? (T)(object)(E) : (T)null
La conversión a object
es necesaria para hacer el uso posible de dynamic
objetos dynamic
. as
es una operación en tiempo de compilación, mientras que dynamic
objetos dynamic
están limitados solo en tiempo de ejecución .
El compilador en realidad trata dynamic
objetos de tipo dynamic
como object
tipo para comenzar con:
class Foo<T>
{
public void SomeMethod()
{
dynamic str = "foo";
Foo<T> f = str as Foo<T>;
}
}
Para empezar, str
se trata como un 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
}
Editar:
Después de hablar con Vladimir Reshetnikov del Equipo de idiomas administrados, él explica lo que la semántica de la representación del "como operador" al "operador de reparto" en realidad trata de convay:
Estoy de acuerdo, hay un lenguaje impreciso en la especificación también. Dice que el operador ''como'' siempre es aplicable si se trata de un tipo abierto, pero luego describe su evaluación en términos de conversiones, lo que podría no ser válido en algunos casos. Debería decir que las conversiones en la expansión no representan un operador de conversión C # normal, sino que solo representan las conversiones permitidas en operadores ''como''. Tomaré una nota para arreglarlo. ¡Gracias!
Acabo de publicar una answer a esta pregunta, pero no estoy del todo convencido de mi respuesta. Hay dos cosas que me pregunto, considera este código:
class Foo<T>
{
void SomeMethod()
{
string str = "foo";
Foo<T> f = str as Foo<T>;
}
}
De acuerdo con la C# Specification 5.0
, hay dos tipos diferentes de conversión de as operator
.
Si el tipo
E
de tiempo de compilación no esdynamic
, la operaciónE as T
produce el mismo resultado que
E is T ? (T)(E) : (T)null
Si el tipo
E
de tiempo de compilación esdynamic
, a diferencia del operador de conversión, el operadoras operator
no está enlazado dinámicamente (§7.2.2). Por lo tanto la expansión en este caso es:
E is T ? (T)(object)(E) : (T)null
Dado que, esto no es válido debido a (Foo<T>)str
str is Foo<T> ? (Foo<T>)str : (Foo<T>)null;
Pensé que debería traducirse como:
str is Foo<T> ? (Foo<T>)(object)str : (Foo<T>)null;
Pero la especificación dice que esto solo sucede cuando el tipo de E
es dynamic
.
Así que mis preguntas son:
- ¿El compilador está traduciendo esta expresión a un código que normalmente no es válido?
- Cuando el tipo de
E
es dinámico, ¿por qué primero convierteE
enobject
luegoT
mientras que la(T)E
es completamente válida?