usar unario ternarios ternario operator operadores operador como asignacion c# null-coalescing-operator c#-6.0

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 a e , excepto si e es de un tipo de valor anulable, en cuyo caso e0 es e.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 es T
  • Si T es (se sabe que es) un tipo de valor no anulable, el tipo de la expresión es T?
  • Si T es (se sabe que es) un tipo de valor anulable, el tipo de la expresión es T
  • 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.



La razón de esto es que acceder al valor con un operador condicional nulo no tendría sentido:

  • Cuando aplica x?.p donde p es un valor no anulable de tipo T , el resultado es de tipo T? . Del mismo modo, el resultado de la operación nullableInt?.Value debe ser anulable.
  • Cuando su Nullable<T> tiene un valor, el resultado de nullableInt?.Value sería el mismo que el valor en sí
  • Cuando su Nullable<T> no tiene un valor, el resultado sería null , 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;