¿Qué significan dos signos de interrogación juntos en C #?

Corrió a través de esta línea de código:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

¿Qué significan los dos signos de interrogación, es una especie de operador ternario? Es difícil buscar en Google.

Es el operador coalescente nulo, y bastante parecido al operador ternario (inmediato si). Ver también ?? Operador – MSDN .

 FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

se expande a:

 FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper(); 

que además se expande a:

 if(formsAuth != null) FormsAuth = formsAuth; else FormsAuth = new FormsAuthenticationWrapper(); 

En inglés, significa “Si lo que sea a la izquierda no es nulo, úsalo, de lo contrario usa lo que está a la derecha”.

Tenga en cuenta que puede usar cualquier cantidad de estos en secuencia. La siguiente statement asignará el primer Answer# to Answer (si todas las respuestas son nulas y la Answer es nula):

 string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4; 

También vale la pena mencionar que aunque la expansión anterior es conceptualmente equivalente, el resultado de cada expresión solo se evalúa una vez. Esto es importante si, por ejemplo, una expresión es una llamada a un método con efectos secundarios. (Crédito a @Joey por señalar esto).

Simplemente porque nadie más ha dicho las palabras mágicas aún: es el operador nulo coalescente . Se define en la sección 7.12 de la especificación del lenguaje C # 3.0 .

Es muy útil, particularmente por la forma en que funciona cuando se usa varias veces en una expresión. Una expresión de la forma:

 a ?? b ?? c ?? d 

dará el resultado de la expresión a si no es nulo; de lo contrario, pruebe b ; de lo contrario, pruebe c ; de lo contrario, pruebe d . Se cortocircuita en cada punto.

Además, si el tipo de d no puede contener nulos, el tipo de la expresión completa tampoco puede contener nulos.

Es el operador coalescente nulo.

http://msdn.microsoft.com/en-us/library/ms173224.aspx

Sí, casi imposible de buscar a menos que sepa cómo se llama. 🙂

EDITAR: Y esta es una característica interesante de otra pregunta. Puedes encadenarlos.

Características ocultas de C #?

Gracias a todos, esta es la explicación más sucinta que encontré en el sitio de MSDN:

 // y = x, unless x is null, in which case y = -1. int y = x ?? -1; 

?? está ahí para proporcionar un valor para un tipo anulable cuando el valor es nulo. Por lo tanto, si formsAuth es nulo, devolverá el nuevo FormsAuthenticationWrapper ().

enter image description here

Los dos signos de interrogación (??) indican que es un operador Coalescente.

El operador coalescente devuelve el primer valor NON-NULL de una cadena. Puedes ver este video de youtube que demuestra todo de manera práctica.

Pero déjame agregar más a lo que dice el video.

Si ves el significado en inglés de coalescer, dice “consolidar juntos”. Por ejemplo, a continuación, se muestra un código coalescente simple que encadena cuatro cadenas.

Entonces, si str1 es null , intentará str2 , si str2 es null , probará str3 y así sucesivamente hasta que encuentre una cadena con un valor no nulo.

 string final = str1 ?? str2 ?? str3 ?? str4; 

En palabras simples, el operador coalescente devuelve el primer valor NON-NULL de una cadena.

Es mano corta para el operador ternario.

 FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper(); 

O para aquellos que no hacen ternario:

 if (formsAuth != null) { FormsAuth = formsAuth; } else { FormsAuth = new FormsAuthenticationWrapper(); } 

Si está familiarizado con Ruby, es ||= parece similar a C # ‘s ?? a mi. Aquí hay algo de Ruby:

 irb(main):001:0> str1 = nil => nil irb(main):002:0> str1 ||= "new value" => "new value" irb(main):003:0> str2 = "old value" => "old value" irb(main):004:0> str2 ||= "another new value" => "old value" irb(main):005:0> str1 => "new value" irb(main):006:0> str2 => "old value" 

Y en C #:

 string str1 = null; str1 = str1 ?? "new value"; string str2 = "old value"; str2 = str2 ?? "another new value"; 

Para su diversión solamente (sabiendo que todos son chicos de C # ;-).

Creo que se originó en Smalltalk, donde ha estado presente por muchos años. Se define allí como:

en Objeto:

 ? anArgument ^ self 

en UndefinedObject (también conocido como clase de nil):

 ? anArgument ^ anArgument 

Hay versiones de evaluación (?) Y no evaluadas (??) de esto.
A menudo se encuentra en getter-methods para variables privadas (instancia) de lazy-lazy, que se dejan en cero hasta que realmente se necesiten.

Nada peligroso sobre esto. De hecho, es hermoso. Puede agregar un valor predeterminado si es deseable, por ejemplo:

CÓDIGO

 int x = x1 ?? x2 ?? x3 ?? x4 ?? 0; 

operador coalescente

es equivalente a

 FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth 

Algunos de los ejemplos aquí de obtener valores usando coalescencia son ineficientes.

Lo que realmente quieres es:

 return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper(); 

o

 return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper()); 

Esto evita que el objeto se vuelva a crear cada vez. En lugar de que la variable privada permanezca nula y se cree un nuevo objeto en cada solicitud, esto garantiza que la variable privada se asigne si se crea el nuevo objeto.

Como señaló correctamente en numerosas respuestas que es el “operador nulo coalescente” ( ?? ), hablando de lo cual también es posible que desee comprobar su primo el “operador condicional nulo” ( ? O ? [ ) Que es un operador que muchas veces se usa junto con ??

Operador nulo-condicional

Se usa para probar null antes de realizar una operación de acceso ( ?. ) O índice ( ? [ ) De miembro. Estos operadores lo ayudan a escribir menos código para manejar las comprobaciones nulas, especialmente para descender a estructuras de datos.

Por ejemplo:

 // if 'customers' or 'Order' property or 'Price' property is null, // dollarAmount will be 0 // otherwise dollarAmount will be equal to 'customers.Order.Price' int dollarAmount = customers?.Order?.Price ?? 0; 

la vieja manera sin ? y ?? de hacer esto es

 int dollarAmount = customers != null && customers.Order!=null && customers.Order.Price!=null ? customers.Order.Price : 0; 

que es más detallado y engorroso.

Nota:

He leído todo este hilo y muchos otros pero no puedo encontrar una respuesta tan completa como esta.

Por lo cual entendí completamente el “por qué usar y cuándo usarlo y cómo usarlo”.

Fuente:

Fundación de comunicación de Windows desatada por Craig McMurtry ISBN 0-672-32948-4

Tipos de valores anulables

Hay dos circunstancias comunes en las que a uno le gustaría saber si se ha asignado un valor a una instancia de un tipo de valor. El primero es cuando la instancia representa un valor en una base de datos. En tal caso, a uno le gustaría poder examinar la instancia para determinar si un valor está realmente presente en la base de datos. La otra circunstancia, que es más pertinente para el tema de este libro, es cuando la instancia representa un elemento de datos recibido de alguna fuente remota. De nuevo, a uno le gustaría determinar a partir de la instancia si se recibió un valor para ese elemento de datos.

.NET Framework 2.0 incorpora una definición de tipo genérico que proporciona casos como estos en los que se desea asignar null a una instancia de un tipo de valor y probar si el valor de la instancia es nulo. Esa definición de tipo genérico es System.Nullable, que restringe los argumentos de tipo genérico que pueden sustituirse por T para valorar tipos. A las instancias de tipos construidos desde System.Nullable se les puede asignar un valor de nulo; de hecho, sus valores son nulos por defecto. Por lo tanto, los tipos construidos a partir de System.Nullable pueden denominarse tipos de valores que aceptan valores de nulos. System.Nullable tiene una propiedad, Valor, mediante la cual el valor asignado a una instancia de un tipo construido a partir de él puede obtenerse si el valor de la instancia no es nulo. Por lo tanto, uno puede escribir:

 System.Nullable myNullableInteger = null; myNullableInteger = 1; if (myNullableInteger != null) { Console.WriteLine(myNullableInteger.Value); } 

El lenguaje de progtwigción C # proporciona una syntax abreviada para declarar tipos construidos a partir de System.Nullable. Esa syntax permite abreviar:

 System.Nullable myNullableInteger; 

a

 int? myNullableInteger; 

El comstackdor evitará que uno intente asignar el valor de un tipo de valor que admite valores NULL a un tipo de valor ordinario de esta manera:

 int? myNullableInteger = null; int myInteger = myNullableInteger; 

Impide que uno lo haga porque el tipo de valor que admite nulos puede tener el valor nulo, que en realidad tendría en este caso, y ese valor no puede asignarse a un tipo de valor ordinario. Aunque el comstackdor permitiría este código,

 int? myNullableInteger = null; int myInteger = myNullableInteger.Value; 

La segunda instrucción provocaría una excepción porque cualquier bash de acceder a la propiedad System.Nullable.Value es una operación no válida si al tipo construido a partir de System.Nullable no se le ha asignado un valor válido de T, que no ha sucedido en este caso.

Conclusión:

Una forma adecuada de asignar el valor de un tipo de valor que admite valores NULL a un tipo de valor ordinario es usar la propiedad System.Nullable.HasValue para determinar si se ha asignado un valor válido de T al tipo de valor que admite valores NULL:

 int? myNullableInteger = null; if (myNullableInteger.HasValue) { int myInteger = myNullableInteger.Value; } 

Otra opción es usar esta syntax:

 int? myNullableInteger = null; int myInteger = myNullableInteger ?? -1; 

Por el cual al entero común myInteger se le asigna el valor del entero nullable “myNullableInteger” si a este último se le ha asignado un valor entero válido; de lo contrario, a myInteger se le asigna el valor de -1.

 FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

es equivalente a

 FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper(); 

Pero lo mejor de todo es que puedes encadenarlos, como dijeron otras personas. La delgada que no se menciona es que puedes usarla para lanzar una excepción.

 A = A ?? B ?? throw new Exception("A and B are both NULL"); 

Es un operador coalescente nulo que funciona de manera similar a un operador ternario.

  a ?? b => a !=null ? a : b 

Otro punto interesante para esto es: “Un tipo que admite nulos puede contener un valor, o puede no estar definido” . Por lo tanto, si intenta asignar un tipo de valor que admite valores NULL a un tipo de valor que no admite nulos, obtendrá un error en tiempo de comstackción.

 int? x = null; // x is nullable value type int z = 0; // z is non-nullable value type z = x; // compile error will be there. 

Entonces, ¿para hacer eso usando? operador:

 z = x ?? 1; // with ?? operator there are no issues