unario - operadores de asignacion en c#
¿El operador condicional nulo no funciona con tipos anulables? (7)
Básicamente estoy de acuerdo con las otras respuestas. Solo esperaba que el comportamiento observado pudiera estar respaldado por alguna forma de documentación autorizada.
Como no puedo encontrar la especificación C # 6.0 en ninguna parte (¿está disponible todavía?), Lo más parecido que encontré a la "documentación" son las Notas de diseño del lenguaje C # para el 3 de febrero de 2014 . Asumiendo que la información encontrada allí todavía refleja el estado actual de las cosas, aquí están las partes relevantes que explican formalmente el comportamiento observado.
La semántica es como aplicar el operador ternario a una verificación de igualdad nula, un literal nulo y una aplicación del operador sin signos de interrogación, excepto que la expresión se evalúa solo una vez:
e?.m(…) => ((e == null) ? null : e0.m(…)) e?.x => ((e == null) ? null : e0.x) e?.$x => ((e == null) ? null : e0.$x) e?[…] => ((e == null) ? null : e0[…])
Donde
e0
es igual ae
, excepto sie
es de un tipo de valor anulable, en cuyo casoe0
ese.Value
.
Aplicando esa última regla a:
nullableInt?.Value
... la expresión semánticamente equivalente se convierte en:
((nullableInt == null) ? null : nullableInt.Value.Value)
Claramente,
nullableInt.Value.Value
no puede compilarse, y eso es lo que observó.
En cuanto a por qué se tomó la decisión de diseño de aplicar esa regla especial específicamente a los tipos anulables, creo que la respuesta de
dasblinkenlight
cubre eso muy bien, por lo que no lo repetiré aquí.
Además, debo mencionar que, incluso si, hipotéticamente, no tuviéramos esta regla especial para los tipos anulables, y la expresión
nullableInt?.Value
y se comportó como pensabas originalmente ...
// let''s pretend that it actually gets converted to this...
((nullableInt == null) ? null : nullableInt.Value)
aun así, la siguiente declaración de su pregunta sería inválida y produciría un error de compilación:
int value = nullableInt?.Value; // still would not compile
La razón por la que todavía no funcionaría es porque el tipo de la expresión
nullableInt?.Value
sería
int?
no
int
.
Entonces, ¿debería cambiar el tipo de la variable de
value
a
int?
.
Esto también está cubierto formalmente en las Notas de diseño de lenguaje C # para el 3 de febrero de 2014 :
El tipo del resultado depende del tipo
T
del lado derecho del operador subyacente:
- Si
T
es (se sabe que es) un tipo de referencia, el tipo de la expresión esT
- Si
T
es (se sabe que es) un tipo de valor no anulable, el tipo de la expresión esT?
- Si
T
es (se sabe que es) un tipo de valor anulable, el tipo de la expresión esT
- De lo contrario (es decir, si no se sabe si
T
es una referencia o un tipo de valor), la expresión es un error de tiempo de compilación.
Pero si se ve obligado a escribir lo siguiente para compilarlo:
int? value = nullableInt?.Value;
... entonces parece bastante inútil, y no sería diferente de simplemente hacer:
int? value = nullableInt;
Como otros han señalado, en su caso, ¿probablemente quiso utilizar el
operador de fusión nula
??
todo el tiempo, no el
operador nulo-condicional
?.
.
Estoy escribiendo un código en c # 6 y por alguna extraña razón esto funciona
var value = objectThatMayBeNull?.property;
pero esto no:
int value = nullableInt?.Value;
Por no funciona quiero decir que recibo un error de compilación que dice
Cannot resolve symbol ''Value''
.
¿Alguna idea de por qué el operador condicional nulo
?.
no funciona
Bien, he pensado y probado algo. Esto es lo que pasa:
int value = nullableInt?.Value;
Da este mensaje de error al compilar:
El tipo ''int'' no contiene una definición para ''Valor''
Eso significa eso
?
''convierte'' el
int?
en el valor
int
real.
Esto es efectivamente lo mismo que:
int value = nullableInt ?? default(int);
El resultado es un número entero, que obviamente no tiene un
Value
.
Bien, ¿podría esto ayudar?
int value = nullableInt?;
No, esa sintaxis no está permitida.
¿Entonces, qué?
Simplemente siga usando
.GetValueOrDefault()
para este caso.
int value = nullableInt.GetValueOrDefault();
Con respecto a los tipos anulables, el
?.
El operador dice que
if not null, use the wrapped value
.
Entonces, para un int anulable, si el anulable tiene un valor
8
, el resultado de
?.
sería
8
, no el nulable que contiene
8
.
Como
Value
no es una propiedad de un
int
, obtienes un error.
Por lo tanto, el ejemplo de intentar usar el
Value
propiedad falla con bastante razón, pero lo siguiente funcionaría,
var x = nullableInt?.ToString();
Considere el operador de fusión nula,
??
.
var x = nullableInt ?? 0;
Aquí, el operador dice,
if null, return 0, otherwise return the value inside the nullable
, que en este caso es un
int
.
El
?.
El operador se desempeña de manera similar con respecto a la extracción del contenido de la anulación.
Para su ejemplo específico, debe usar el
??
operador y un valor predeterminado apropiado en lugar de
?.
operador.
El operador condicional nulo también desenvuelve la variable anulable. Entonces después del "?" operador, la propiedad "Valor" ya no es necesaria.
Escribí una publicación que detalla más cómo encontré esto. En caso de que te lo estés preguntando
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
La razón de esto es que acceder al valor con un operador condicional nulo no tendría sentido:
-
Cuando aplica
x?.p
dondep
es un valor no anulable de tipoT
, el resultado es de tipoT?
. Del mismo modo, el resultado de la operaciónnullableInt?.Value
debe ser anulable. -
Cuando su
Nullable<T>
tiene un valor, el resultado denullableInt?.Value
sería el mismo que el valor en sí -
Cuando su
Nullable<T>
no tiene un valor, el resultado seríanull
, que es, de nuevo, el mismo que el valor en sí.
Aunque no tiene sentido acceder a
Value
con el
?.
operador, tiene sentido acceder a otras propiedades de tipos de valores anulables.
El operador trabaja de manera coherente con los tipos de valores anulables y con los tipos de referencia, por lo que estas dos implementaciones producen un comportamiento idéntico:
class PointClass {
public int X { get; }
public int Y { get; }
public PointClass(int x, int y) { X = x; Y = y; }
}
struct PointStruct {
public int X { get; }
public int Y { get; }
public PointStruct(int x, int y) { X = x; Y = y; }
}
...
PointClass pc = ...
PointStruct? ps = ...
int? x = pc?.X;
int? y = ps?.Y;
En el caso de una
struct
anulable, el operador le permite acceder a una propiedad del tipo subyacente
PointStruct
, y agrega nulabilidad al resultado de la misma manera que lo hace para las propiedades no anulables del tipo de referencia
PointClass
.
Simplemente porque (basado en la respuesta de sstan arriba)
var value = objectThatMayBeNull?.property;
es evaluado por el compilador como
var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property
y
int value = nullableInt?.Value;
me gusta
int value = (nullableInt == null) ? null : nullableInt.Value.Value;
cuando
nullableInt.Value.Value
es
Cannot resolve symbol ''Value''
se
Cannot resolve symbol ''Value''
error de sintaxis del
Cannot resolve symbol ''Value''
.
int
no tiene una propiedad
Value
.
Considerar:
var value = obj?.Property
Es equivalente a:
value = obj == null ? null : obj.Property;
Eso no tiene sentido con
int
y por lo tanto no con
int?
vía
?.
¿El antiguo
GetValueOrDefault()
tiene sentido con
int?
.
O para el caso,
?
desde entonces
?
tiene que devolver algo anulable, simplemente:
int? value = nullableInt;