c# - validar - cambiar con var/nulo comportamiento extraño
operador null c# (3)
Dentro de una instrucción de
switch
coincidencia de patrón que usa un
case
para un tipo explícito se pregunta si el valor en cuestión es de ese tipo específico o de un tipo derivado.
Es el equivalente exacto de
is
switch (someString) {
case string s:
}
if (someString is string)
El valor
null
no tiene un tipo y, por lo tanto, no cumple ninguna de las condiciones anteriores.
El tipo estático de
someString
no entra en juego en ninguno de los ejemplos.
Sin embargo, el tipo
var
en la coincidencia de patrones actúa como comodín y coincidirá con cualquier valor, incluido
null
.
El caso
default
aquí es código muerto.
El
case var o
coincidirá con cualquier valor, nulo o no nulo.
Un caso no predeterminado siempre prevalece sobre uno
default
,
default
tanto, el
default
nunca será afectado.
Si miras el IL, verás que ni siquiera se emite.
De un vistazo, puede parecer extraño que esto se compile sin ninguna advertencia (definitivamente me desanimó).
Pero esto coincide con el comportamiento de C # que se remonta a 1.0.
El compilador permite casos
default
incluso cuando puede probar trivialmente que nunca será afectado.
Considere como ejemplo lo siguiente:
bool b = ...;
switch (b) {
case true: ...
case false: ...
default: ...
}
Aquí el
default
nunca se verá afectado (incluso para
bool
que tiene un valor que no es 1 o 0).
Sin embargo, C # ha permitido esto desde 1.0 sin previo aviso.
La coincidencia de patrones simplemente coincide con este comportamiento aquí.
Dado el siguiente código:
string someString = null;
switch (someString)
{
case string s:
Console.WriteLine("string s");
break;
case var o:
Console.WriteLine("var o");
break;
default:
Console.WriteLine("default");
break;
}
¿Por qué coincide la sentencia switch en el
case var o
?
Tengo entendido que la
case string s
no coincide cuando
s == null
porque (efectivamente)
(null as string) != null
evalúa como falso.
IntelliSense en VS Code me dice que
o
es una
string
.
¿Alguna idea?
Similar a: C # 7 caso de interruptor con cheques nulos
Es porque el
case <Type>
coincide con el tipo
dinámico
(tiempo de ejecución), no con el tipo estático (tiempo de compilación).
null
no tiene un tipo dinámico, por lo que no puede coincidir con una
string
.
var
es solo la alternativa.
(Publicando porque me gustan las respuestas cortas).
Estoy reuniendo varios comentarios de Twitter aquí; esto es realmente nuevo para mí, y espero que jaredpar salte con una respuesta más completa, pero; versión corta como la entiendo:
case string s:
se interpreta como
if(someString is string) { s = (string)someString; ...
if(someString is string) { s = (string)someString; ...
o
if((s = (someString as string)) != null) { ... }
- cualquiera de los cuales implica una prueba
null
- que falló en su caso;
a la inversa:
case var o:
donde el compilador resuelve
o
como
string
es simplemente
o = (string)someString; ...
o = (string)someString; ...
- no hay prueba
null
, a
pesar de
que se ve similar en la superficie, solo con el compilador que proporciona el tipo.
finalmente:
default:
aquí no se puede alcanzar , porque el caso anterior atrapa todo. Esto puede ser un error del compilador porque no emitió una advertencia de código inalcanzable.
Estoy de acuerdo en que esto es
muy
sutil, matizado y confuso.
Pero aparentemente el
case var o
escenario tiene usos con propagación nula (
o?.Length ?? 0
etc.).
Estoy de acuerdo en que es extraño que esto funcione de manera
muy
diferente entre
var o
y
string s
, pero es lo que hace actualmente el compilador.