c# - unreachable code detected angular 5
¿Por qué este código no es inalcanzable? (4)
El análisis estático solo puede hacer mucho, y solo marcará el código como inaccesible si puede probar que un valor no se puede cambiar. En su código, lo que sucede dentro de Bar
está fuera del alcance del flujo del método y no se puede razonar estáticamente. ¿Qué Bar
si el constructor de Bar
lanza un subproceso que establece el valor del type
nuevo en B
? El compilador no puede saberlo, porque, nuevamente, las partes internas de Bar
no están sujetas al método.
Si su código estaba verificando el valor de una variable local , entonces el compilador podría saber si no había forma de cambiar. Pero ese no es el caso aquí.
Encontré un caso donde tengo un código que creo que es inalcanzable y no se detecta. Ninguna advertencia es emitida ni por el compilador ni por Visual Studio.
Considere este código:
enum Foo { A, B, C }
class Bar { public Foo type; }
static class Program
{
private static void Main()
{
var bar = new Bar { type = Foo.A };
if (bar.type == Foo.B)
{
Console.WriteLine("lol");
}
}
}
Obviamente, el programa no imprimirá "lol" porque la condición en la sentencia if es falsa. No entiendo por qué no se emite una advertencia para el código inalcanzable. Mi única hipótesis es que eso podría ser alcanzable si tienes una condición de carrera en un programa de múltiples subprocesos. ¿Es esto correcto?
La especificación de C # dice,
La primera instrucción incrustada de una instrucción if es accesible si la instrucción if es accesible y la expresión booleana no tiene el valor constante falso.
y, en cuanto a expresiones constantes ,
Una expresión constante debe ser el literal nulo o un valor con uno de los siguientes tipos: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, string o cualquier otro tipo de enumeración.
Solo se permiten las siguientes construcciones en expresiones constantes:
- Literales (incluido el literal
null
).- Referencias a los miembros const de los tipos class y struct.
- Referencias a miembros de tipos de enumeración.
- Referencias a parámetros const o variables locales.
- Subexpresiones entre paréntesis, que a su vez son expresiones constantes.
- Expresiones de conversión, siempre que el tipo de destino sea uno de los tipos enumerados anteriormente. Expresiones marcadas y sin marcar
- Expresiones de valor predeterminado
- Lo predefinido
+
,–
!
, y~
operadores unarios.- Lo predefinido
+
,–
,*
,/
,%
,<<
,>>
,&
, |,^
,&&
,||
,==
!=
,<
,>
,<=
, y>=
operadores binarios, siempre que cada operando sea del tipo indicado anteriormente.- El
?:
Operador condicional.
Las expresiones de acceso de miembros no están en esta lista, por lo que la expresión booleana no es constante. Así el cuerpo del bloque if es alcanzable.
La advertencia que esperaba no se implementó porque no es una advertencia útil.
En las aplicaciones del mundo real, el compilador se enfrenta a menudo con un código que puede demostrar que es inalcanzable, tal vez incluso algo tan calvo como
static class Program
{
private static void Main()
{
if (false)
{
Console.WriteLine("lol");
}
}
}
No tengo un compilador de C # en esta computadora, pero apuesto a que tampoco hay ninguna advertencia para eso. Esto se debe a que, cuando coloca if (false) { ... }
alrededor de un bloque de código, lo hizo a propósito, tal vez para deshabilitar algo temporalmente para un experimento. Molestarte por eso no sería útil.
Más común es que no es un literal false
, es una constante de compilación que el sistema de compilación establecerá en verdadero o falso según la configuración; desea que el compilador elimine el código inalcanzable en una compilación pero no en la otra, y no desea quejas de ninguna manera.
Incluso más común que eso es para las primeras optimizaciones, como la alineación y la propagación constante, para descubrir que un condicional siempre es falso; Supongamos que tienes algo como
static class Program
{
private static void Fizz(int i)
{
if (i % 3 == 0) {
Console.WriteLine("fizz");
} else {
Console.WriteLine(i);
}
}
private static void Main()
{
Fizz(4);
}
}
Claramente, no querrá que le digan que un lado del condicional dentro de Fizz () era inalcanzable solo porque solo se lo llamó con el argumento 4 en este programa .
Porque no se puede hacer tal garantía en tiempo de compilación. Considera esta clase de bar alternativa.
class Bar
{
Random random = new Random();
Array Foos = Enum.GetValues(typeof(Foo));
private Foo _type;
public Foo type
{
get { return _type; }
set
{
_type = (Foo)Foos.GetValue(random.Next(3));
}
}
}
Tenga en cuenta que "accesible" se define a nivel de función. No está permitido salir de la función que se está probando, incluso cuando es seguro hacerlo.