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 falta algo o al compilador no le gusta mi ||
?
He reducido esto para dynamic
causar los problemas ( options
era una variable dinámica en mi código anterior). La pregunta sigue siendo, ¿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 sí :
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 dynamic
que sería un factor en esto.
out
parámetro como entradaout
parámetro. Ciertamente es interesante considerar qué código auxiliar debería producir el compilador para evitar el problema, o si eso es posible.Respuestas:
Estoy bastante seguro de que se trata de un error del compilador. ¡Buen hallazgo!
Editar: no es un error, como demuestra Quartermeister; dynamic podría implementar un
true
operador extraño que podría causary
que nunca se inicialice.Aquí hay una reproducción mínima:
No veo ninguna razón por la que eso deba ser ilegal; si reemplaza dynamic con bool, se compila bien.
De hecho, mañana me reuniré con el equipo de C #; Se lo mencionaré. ¡Disculpas por el error!
fuente
d
puede ser de un tipo con untrue
operador sobrecargado . Publiqué una respuesta con un ejemplo en el que no se toma ninguna rama.Es posible que la variable no esté asignada si el valor de la expresión dinámica es de un tipo con un operador sobrecargado
true
.El
||
operador invocará altrue
operador para decidir si evaluar el lado derecho, y luego laif
declaración invocará altrue
operador para decidir si evaluar su cuerpo. Para una normalbool
, estos siempre devolverán el mismo resultado y, por lo tanto, 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:
fuente
d
evaluarse dos veces? (No estoy discutiendo que claramente lo sea , como ha mostrado). Hubiera esperado que el resultado evaluado detrue
(desde la primera invocación del operador, causa por||
) se "pasara" a laif
declaración. Eso es ciertamente lo que sucedería si pones una llamada de función allí, por ejemplo.d
se evalúa solo una vez, como es de esperar. Es eltrue
operador el que se invoca dos veces, una por||
una y otra porif
.var cond = d || M(out y); if (cond) { ... }
. Primero evaluamosd
para obtener unaEvilBool
referencia de objeto. Para evaluar el||
, primero invocamosEvilBool.true
con esa referencia. Eso devuelve verdadero, por lo que cortocircuitamos y no invocamosM
, y luego asignamos la referencia acond
. Luego, pasamos a laif
declaración. Laif
declaración evalúa su condición llamandoEvilBool.true
.De MSDN (el énfasis es mío):
Dado que el compilador no comprueba el tipo ni resuelve ninguna operación que contenga expresiones de tipo dinámico, no puede asegurar que la variable se asignará mediante el uso de
TryParse()
.fuente
numberGroups
se asigna (en elif true
bloque), si no, la segunda condición garantiza la asignación (víaout
).myString == null
(confiando solo enTryParse
).if
expresión completa ) involucra unadynamic
variable, no se resuelve en el momento de la compilación (el compilador, por lo tanto, no puede hacer esas suposiciones).