2010-06-02 10 views
10

tengo problemas para entender lo que la hace que el error de compilación en el código de abajo:comportamiento de conexión extraño en .NET 4

static class Program 
{ 
    static void Main() 
    { 
     dynamic x = ""; 
     var test = foo(x); 

     if (test == "test") 
     { 
      Console.WriteLine(test); 
     } 

     switch (test) 
     { 
      case "test": 
       Console.WriteLine(test); 
       break; 
     } 
    } 

    private static string foo(object item) 
    { 
     return "bar"; 
    } 
} 

El error que consigo es en switch (test) línea:

A switch expression or case label must be a bool, char, string, integral, 
enum, or corresponding nullable type. 

espectáculos Intellisence esa operación foo se resolverá en tiempo de ejecución, lo cual está bien porque estoy usando un tipo dinámico como un param. Sin embargo, no entiendo cómo se compila bien la condición if cuando el interruptor no lo hace.

El código anterior es simplemente una versión simplificada de lo que tengo en mi aplicación (VSTO) que apareció después de migrar la aplicación de VSTO3 a VSTO4 cuando un método en VSTO cambiaba para devolver dynamic valores de tipo en lugar de object.

¿Alguien puede darme una explicación cuál es el problema. Sé cómo resolverlo, pero me gustaría entender qué está pasando.

+0

Parece que no se puede utilizar un conmutador –

+0

Como 'switch' no está definido para todos los objetos posibles tipo – thecoop

+0

Todo el mundo parece responder como si la pregunta fuera" ¿Por qué no puedo 'cambiar' en un' dynamic '?" Creo que la pregunta realmente debería ser "¿Por qué' test' tipado como 'dinámico' en primer lugar?" Entiendo que * if * 'foo' tenía sobrecargas que devolvían diferentes tipos,' test' tendría que ser 'dynamic'; pero dado que * no *, sigo teniendo problemas para encontrar la respuesta a la pregunta "real" aquí. –

Respuesta

10

Debido a que usted está llamando a un método de forma dinámica, el resultado es también un dynamic (como el valor de retorno es nada - no se sabe hasta el tiempo de ejecución). Y no puede switch en un tipo de variable dynamic.

+0

¿Y está bien 'if' on' dynamic'? – RaYell

+0

@RaYell: No "' if' on 'dynamic'" - se compara con igualdad '==' en 'dynamic'. Eso está bien definido. – Niki

+0

OK, eso tiene sentido. – RaYell

0

Esto es un comportamiento inesperado: esperaba un conjunto de var para un método que devuelve explícitamente una cadena para inferir correctamente un tipo de cadena. Oh, bueno .....

Si reemplaza:

var test = foo (x);

con:

cadena de prueba = foo (x);

todo compila como usted sabe.

Esto es seguro ya que has declarado que foo() devuelve una cadena, y tal vez un poco más intuitiva de leer en el largo plazo de todos modos.

+0

la 'var' no se puede resolver en el tiempo de ejecución porque x es dinámico. Es posible que existan múltiples sobrecargas de 'foo' que tengan diferentes parámetros y tipos de retorno.Exactamente lo que sucede no se puede resolver hasta que se conozca el tipo de x, lo que no sucederá hasta el tiempo de ejecución. lo que sucede en realidad es que var se resuelve en 'dinámico', por lo que no se puede usar en el cambio. Si coloca el puntero del mouse sobre la 'var', verá que Visual Studio lo está resolviendo como 'dinámico'. –

+0

Sí, estoy viendo eso. Supongo que simplemente asumí que la inferencia de var era más inteligente cuando se enfrentaba a la presencia de un único método en el ámbito donde se realizó la llamada al método. Pero sabes lo que dicen sobre las suposiciones ... =) –

3

El tipo de expresión del modificador es evaluado por el compilador, en tiempo de compilación. El tipo de dynamic se evalúa en tiempo de ejecución, por lo que el compilador no puede verificar si es (o es convertible) uno de los tipos permitidos (que, de acuerdo con C# 4 Language Specification es sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string o un tipo enum).

2

Como dice Matt Ellen, pero con un poco más de fondo.

Para la declaración switch: Del C# Language Specification v4.0:

El tipo de gobierno de una declaración switch se establece por la expresión switch.

  • Si el tipo de la expresión switch es sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, o un enumeración de tipo, o si es el anulable tipo correspondiente a uno de estos tipos, entonces ese es el tipo de gobierno de la declaración switch.
  • De lo contrario, exactamente una conversión implícita definida por el usuario (§6.4) debe existir desde el tipo de la expresión cambiar a uno de los siguientes tipos de gobierno posibles: sbyte, byte, short, ushort, int, uint, long, ulong, char, string, o, un tipo anulable correspondiente a uno de esos tipos.
  • De lo contrario, si no existe tal conversión implícita, o si existe más de una conversión implícita de este tipo, se produce un error en tiempo de compilación.

Para la declaración if la expresión se evalúa como una operación booleana. La evaluación de expresión se difiere al tiempo de ejecución debido al uso de dynamic en la llamada a método en la asignación de variable. De la especificación anterior, parece que switch requiere una evaluación en tiempo de compilación de los tipos de conmutadores.

0

Las sentencias de cambio solo admiten números, caracteres, enumeraciones y cadenas. dynamic no es ninguna de esas cosas. Si se estima que x es una cadena, puede simplemente echarlo:

dynamic x = ""; 
string test = (string)foo(x); 

vas a tener un error de ejecución si no lo es.