type try switch statement operator not net cast asp c# .net dynamic casting as-operator

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 es dynamic , la operación E as T produce el mismo resultado que

E is T ? (T)(E) : (T)null

Si el tipo E de tiempo de compilación es dynamic , a diferencia del operador de conversión, el operador as 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:

  1. ¿El compilador está traduciendo esta expresión a un código que normalmente no es válido?
  2. Cuando el tipo de E es dinámico, ¿por qué primero convierte E en object luego T mientras que la (T)E es completamente válida?