visual studio solucion realizo que puedo porque los han generarse generar error diseñador confirmado compilar compila como codigo cambios c# .net linq roslyn

c# - studio - Roslyn no pudo compilar el código



roslyn c# (4)

¿Qué causa este problema?

A mí me parece un error del compilador. Al menos lo hizo. Aunque las decimal.TryParse(v, out a) y decimal.TryParse(v, out b) se evalúan dinámicamente, esperaba que el compilador todavía entendiera que cuando llega a <= b , tanto a como b son definitivamente asignado Incluso con las rarezas que puede encontrar en la escritura dinámica, esperaría evaluar solo a <= b después de evaluar las TryParse llamadas TryParse .

Sin embargo, resulta que a través del operador y la conversión es difícil, es completamente factible tener una expresión A && B && C que evalúa A y C pero no B , si eres lo suficientemente astuto. Vea el informe de error de Roslyn para el ingenioso ejemplo de Neal Gafter.

Hacer que el trabajo con dynamic sea ​​aún más difícil: la semántica involucrada cuando los operandos son dinámicos es más difícil de describir, porque para realizar la resolución de sobrecarga, debe evaluar los operandos para descubrir qué tipos están involucrados, lo que puede ser contra-intuitivo. Sin embargo, nuevamente Neal ha presentado un ejemplo que muestra que se requiere el error del compilador ... esto no es un error, es una corrección de errores. Enormes cantidades de felicitaciones a Neal por probarlo.

¿Es posible arreglarlo a través de la configuración del compilador?

No, pero hay alternativas que evitan el error.

En primer lugar, puede evitar que sea dinámico: si sabe que solo usará cadenas, podría usar IEnumerable<string> o IEnumerable<string> a la variable de rango v un tipo de string (es decir, from string v in array ). Esa sería mi opción preferida.

Si realmente necesitas mantenerlo dinámico, solo dale un valor a b para comenzar:

decimal a, b = 0m;

Esto no hará ningún daño: sabemos que en realidad su evaluación dinámica no hará nada loco, por lo que aún terminará asignando un valor a b antes de usarlo, haciendo que el valor inicial sea irrelevante.

Además, parece que agregar paréntesis también funciona:

where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)

Eso cambia el punto en el que se activan varias piezas de resolución de sobrecarga, y sucede que hace feliz al compilador.

Todavía queda un problema: las reglas de la especificación sobre la asignación definitiva con el operador && deben aclararse para indicar que solo se aplican cuando el operador && se está utilizando en su implementación "regular" con dos operandos bool . Trataré de asegurarme de que esto se arregle para el próximo estándar ECMA.

Después de haber migrado mi proyecto de VS2013 a VS2015, el proyecto ya no se compila. Se produce un error de compilación en la siguiente instrucción LINQ:

static void Main(string[] args) { decimal a, b; IEnumerable<dynamic> array = new string[] { "10", "20", "30" }; var result = (from v in array where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here orderby decimal.Parse(v) select v).ToArray(); }

El compilador devuelve un error:

Error CS0165 Uso de la variable local no asignada ''b''

¿Qué causa este problema? ¿Es posible arreglarlo a través de una configuración de compilador?


Como me educaron tanto en el informe de error, voy a tratar de explicarlo yo mismo.

Imagine T es un tipo definido por el usuario con una conversión implícita a bool que alterna entre false y true , comenzando con false . Hasta donde el compilador sabe, el primer argumento dynamic para el primer && podría evaluar ese tipo, por lo que tiene que ser pesimista.

Si, entonces, deja compilar el código, esto podría suceder:

  • Cuando la carpeta dinámica evalúa el primer && , hace lo siguiente:
    • Evalúa el primer argumento
    • Es una T , implícitamente lo echó a bool .
    • Oh, es false , por lo que no necesitamos evaluar el segundo argumento.
    • Haga que el resultado de && evalúe como primer argumento. (No, no es false , por alguna razón).
  • Cuando la carpeta dinámica evalúa el segundo && , hace lo siguiente:
    • Evalúa el primer argumento.
    • Es una T , implícitamente lo echó a bool .
    • Oh, es true , así que evalúa el segundo argumento.
    • ... Oh, mierda, b no está asignado.

En términos específicos, en resumen, hay reglas especiales de "asignación definida" que nos permiten decir no solo si una variable está "definitivamente asignada" o "no está definitivamente asignada", sino también si está "definitivamente asignada después de false declaración false " o " definitivamente asignado después de true declaración true ".

Estos existen para que cuando se trata de && y || (y ! y ?? y ?: :) el compilador puede examinar si las variables pueden asignarse en ramas particulares de una expresión booleana compleja.

Sin embargo, estos solo funcionan mientras los tipos de expresiones permanecen booleanos . Cuando parte de la expresión es dynamic (o un tipo estático no booleano) ya no podemos decir de manera confiable que la expresión es true o false ; la próxima vez que la bool en bool para decidir qué rama tomar, puede haber cambiado su mente.

Actualización: esto ya se ha resolved y documented :

Las reglas de asignación definidas implementadas por compiladores anteriores para expresiones dinámicas permitieron algunos casos de código que podrían resultar en la lectura de variables que no están asignadas definitivamente. Ver https://github.com/dotnet/roslyn/issues/4509 para un informe de esto.

...

Debido a esta posibilidad, el compilador no debe permitir que este programa se compile si val no tiene un valor inicial. Las versiones anteriores del compilador (anteriores a VS2015) permitieron que este programa se compilara incluso si val no tiene un valor inicial. Roslyn ahora diagnostica este intento de leer una variable posiblemente no inicializada.



Esto parece ser un error, o al menos una regresión, en el compilador de Roslyn. Se ha archivado el siguiente error para rastrearlo:

https://github.com/dotnet/roslyn/issues/4509

Mientras tanto, la excelente respuesta de Jon tiene un par de soluciones.