new functions c# c#-4.0 dynamic compiler-construction cil

c# - functions - ¿Por qué este resultado condicional(nulo ||! TryParse) en "uso de variable local no asignada"?



static dynamic c# (3)

El siguiente código da como resultado el uso de la variable local no asignada "numberOfGroups" :

int numberOfGroups; if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups)) { numberOfGroups = 10; }

Sin embargo, este código funciona bien (aunque, ReSharper dice que = 10 es redundante):

int numberOfGroups = 10; if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups)) { numberOfGroups = 10; }

Me estoy perdiendo algo, o al compilador no le gusta mi || ?

He reducido esto a dynamic causando los problemas (las options eran una variable dinámica en mi código anterior). La pregunta aún permanece, ¿por qué no puedo hacer esto ?

Este código no se compila:

internal class Program { #region Static Methods private static void Main(string[] args) { dynamic myString = args[0]; int myInt; if(myString == null || !int.TryParse(myString, out myInt)) { myInt = 10; } Console.WriteLine(myInt); } #endregion }

Sin embargo, este código hace :

internal class Program { #region Static Methods private static void Main(string[] args) { var myString = args[0]; // var would be string int myInt; if(myString == null || !int.TryParse(myString, out myInt)) { myInt = 10; } Console.WriteLine(myInt); } #endregion }

No me di cuenta de que la dynamic sería un factor en esto.


Es posible que la variable no esté asignada si el valor de la expresión dinámica es de un tipo con un operador true sobrecargado .

El || el operador invocará al operador true para decidir si evalúa el lado derecho, y luego el enunciado if invocará al operador true para decidir si evalúa su cuerpo. Para un bool normal, estos siempre devolverán el mismo resultado, por lo que se evaluará exactamente uno, pero para un operador definido por el usuario ¡no existe tal garantía!

Partiendo de la reproducción de Eric Lippert, aquí hay un programa corto y completo que demuestra un caso en el que ninguna ruta se ejecutaría y la variable tendría su valor inicial:

using System; class Program { static bool M(out int x) { x = 123; return true; } static int N(dynamic d) { int y = 3; if (d || M(out y)) y = 10; return y; } static void Main(string[] args) { var result = N(new EvilBool()); // Prints 3! Console.WriteLine(result); } } class EvilBool { private bool value; public static bool operator true(EvilBool b) { // Return true the first time this is called // and false the second time b.value = !b.value; return b.value; } public static bool operator false(EvilBool b) { throw new NotImplementedException(); } }


Estoy bastante seguro de que esto es un error del compilador. Buen hallazgo!

Editar: no es un error, como lo demuestra Quartermeister; dynamic podría implementar un operador true extraño que podría causar que y nunca se inicialice.

Aquí hay una reproducción mínima:

class Program { static bool M(out int x) { x = 123; return true; } static int N(dynamic d) { int y; if(d || M(out y)) y = 10; return y; } }

No veo ninguna razón por la que eso debería ser ilegal; si reemplazas dynamic con bool compila muy bien.

De hecho, me reuniré con el equipo de C # mañana; Lo mencionaré a ellos. Disculpas por el error!


De MSDN (énfasis mío):

El tipo dinámico permite que las operaciones en las que ocurre omitan la verificación de tipos en tiempo de compilación . En cambio, estas operaciones se resuelven en tiempo de ejecución . El tipo dinámico simplifica el acceso a las API COM, como las API de automatización de Office, y también a las API dinámicas, como las bibliotecas de IronPython, y al Modelo de objetos de documento HTML (DOM).

Tipo dinámico se comporta como tipo de objeto en la mayoría de las circunstancias. Sin embargo, las operaciones que contienen expresiones de tipo dinámico no se resuelven o el tipo comprueba el compilador.

Como el compilador no escribe check o resuelve ninguna operación que contenga expresiones de tipo dinámico, no puede garantizar que la variable se asigne mediante el uso de TryParse() .