Corrió a través de esta línea de código:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
¿Qué significan los dos signos de interrogación, es algún tipo de operador ternario? Es difícil buscar en Google.
Corrió a través de esta línea de código:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
¿Qué significan los dos signos de interrogación, es algún tipo de operador ternario? Es difícil buscar en Google.
Respuestas:
Es el operador de fusión nula, 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 se expande aún más a:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
En inglés, significa "Si lo que está a la izquierda no es nulo, úselo, de lo contrario use lo que está a la derecha".
Tenga en cuenta que puede usar cualquier número de estos en secuencia. La siguiente instrucción asignará la primera no nula Answer#
a Answer
(si todas las respuestas son nulas, entonces la Answer
es nula):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
También vale la pena mencionar que si bien 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. (Gracias a @Joey por señalar esto).
??
se deja asociativo, por lo que a ?? b ?? c ?? d
es equivalente a ((a ?? b) ?? c ) ?? d
. "Los operadores de asignación y el operador ternario (? :) son asociativos correctos. Todos los demás operadores binarios quedan asociativos". Fuente: msdn.microsoft.com/en-us/library/ms173145.aspx
Solo porque nadie más ha dicho las palabras mágicas todavía: es el operador de fusión nulo . Está definido 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 intente b
, de lo contrario intente c
, de lo contrario intente d
. Cortocircuita en cada punto.
Además, si el tipo de d
no es anulable, el tipo de la expresión completa tampoco lo es.
Es el operador de fusión nulo.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
Sí, casi imposible de buscar a menos que sepas cómo se llama. :-)
EDITAR: Y esta es una característica genial de otra pregunta. Puedes encadenarlos.
Gracias a todos, aquí está 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;
-1
es simplemente un simple int
, que no es anulable).
x
es de tipo int?
, pero y
es de tipo int
, podría escribir int y = (int)(x ?? -1)
. Se analizará x
a un int
si no es null
, o se asignará -1
a y
si x
es null
.
Los dos signos de interrogación (??) indican que es un operador de fusión.
El operador coalescente devuelve el primer valor NO NULL de una cadena. Puedes ver este video de youtube que demuestra prácticamente todo.
Pero déjenme agregar más a lo que dice el video.
Si ve el significado en inglés de fusión, dice "consolidar juntos". Por ejemplo, a continuación se muestra un código de fusión simple que encadena cuatro cadenas.
Así que si str1
es null
que va a tratar str2
, si str2
es null
que va a tratar str3
y así sucesivamente hasta que encuentra una cadena con un valor no nulo.
string final = str1 ?? str2 ?? str3 ?? str4;
En palabras simples, el operador de fusión devuelve el primer valor NO NULL de una cadena.
Es una mano corta para el operador ternario.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
O para aquellos que no hacen ternary:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
) como la segunda formsAuth
(después de la ?
) podrían modificarse; en la forma de fusión nula, ambos toman implícitamente los valores que ha proporcionado.
Si estás familiarizado con Ruby, me ||=
parece similar a C # ??
. Aquí hay un poco 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";
x ||= y
se desugará a algo así x = x || y
, por ??
lo que en realidad es más similar a la simple ||
en Ruby.
??
sólo se preocupa null
, mientras que el ||
operador de Ruby, al igual que en la mayoría de lenguajes, es más acerca de null
, false
o todo lo que puede ser considerado como un booleano con un valor de false
(por ejemplo, en algunos idiomas, ""
). Esto no es algo bueno o malo, simplemente una diferencia.
Nada peligroso sobre esto. De hecho, es hermoso. Puede agregar valor predeterminado si eso es conveniente, por ejemplo:
CÓDIGO
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
¿Es correcto
x1
- x4
DEBE ser tipos anulables: no tiene sentido decir, efectivamente, "el resultado es 0
si x4
es un valor que no puede tomar" ( null
). El "tipo anulable" aquí incluye tanto los tipos de valores anulables como los tipos de referencia, por supuesto. Es un error en tiempo de compilación si una o más de las variables encadenadas (excepto la última) no son anulables.
Como se señaló correctamente en numerosas respuestas, ese es el "operador de fusión nula" ( ?? ), hablando de lo cual es posible que también desee consultar a su primo el "Operador condicional nulo" ( ?. O ? [ ) Que es un operador que muchas veces se usa junto con ??
Se usa para probar nulo antes de realizar una operación de acceso de miembro ( ?. ) O índice ( ? [ ). Estos operadores lo ayudan a escribir menos código para manejar verificaciones 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;
a la antigua usanza 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.
Solo para su diversión (sabiendo que son todos C # chicos ;-).
Creo que se originó en Smalltalk, donde ha existido durante muchos años. Se define allí como:
en objeto:
? anArgument
^ self
en UndefinedObject (también conocido como clase nula):
? anArgument
^ anArgument
Hay versiones de evaluación (?) Y no evaluables (??) de esto.
A menudo se encuentra en métodos getter para variables privadas (instancia) de inicialización lenta, que se dejan en cero hasta que realmente se necesitan.
Algunos de los ejemplos aquí de obtener valores utilizando la fusión 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.
??
evalúa el atajo? new FormsAuthenticationWrapper();
se evalúa si y solo si _formsAuthWrapper
es nulo.
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 usar ?? y cómo usar ??".
Base de comunicación de Windows desatada por Craig McMurtry ISBN 0-672-32948-4
Hay dos circunstancias comunes en las que uno quisiera saber si un valor ha sido asignado a una instancia de un tipo de valor. La primera 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 al tema de este libro, es cuando la instancia representa un elemento de datos recibido de alguna fuente remota. Nuevamente, uno quisiera 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 un valor nulo a una instancia de un tipo de valor y comprobar 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 ser sustituidos por T a los tipos de valor. Las instancias de tipos construidos a partir de System.Nullable pueden tener asignado un valor nulo; de hecho, sus valores son nulos por defecto. Por lo tanto, los tipos construidos a partir de System.Nullable pueden denominarse tipos de valor anulables. System.Nullable tiene una propiedad, Value, por la cual el valor asignado a una instancia de un tipo construido a partir de él se puede obtener si el valor de la instancia no es nulo. Por lo tanto, uno puede escribir:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
El lenguaje de programación C # proporciona una sintaxis abreviada para declarar tipos construidos a partir de System.Nullable. Esa sintaxis permite abreviar:
System.Nullable<int> myNullableInteger;
a
int? myNullableInteger;
El compilador evitará que uno intente asignar el valor de un tipo de valor anulable 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 anulable podría 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 compilador permitiría este código,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
La segunda declaración provocaría una excepción porque cualquier intento 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, lo que no ha sucedido en este caso.
Una forma adecuada de asignar el valor de un tipo de valor anulable 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 anulable:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Otra opción es usar esta sintaxis:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
Por el cual se asigna al entero común myInteger el valor del entero anulable "myNullableInteger" si a este último se le ha asignado un valor entero válido; de lo contrario, myInteger tiene asignado el valor de -1.
Es un operador de fusión nula que funciona de manera similar a un operador ternario.
a ?? b => a !=null ? a : b
Otro punto interesante para esto es, "Un tipo anulable puede contener un valor, o puede ser indefinido" . Entonces, si intenta asignar un tipo de valor anulable a un tipo de valor no anulable, obtendrá un error en tiempo de compilació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.
¿Para hacer eso usando? operador:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
es equivalente a
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Pero lo bueno de esto es que puedes encadenarlos, como dijeron otras personas. Lo único que no se menciona es que en realidad puedes usarlo para lanzar una excepción.
A = A ?? B ?? throw new Exception("A and B are both NULL");
El ??
operador se llama operador de fusión nula. Devuelve el operando de la izquierda si el operando no es nulo; de lo contrario, devuelve el operando de la derecha.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Establezca variable2
el valor de variable1
, si variable1
NO es nulo; de lo contrario, si se variable1 == null
establece variable2
en 100.
Otros han descrito lo Null Coalescing Operator
bastante bien. Para aquellos interesados, hay una sintaxis abreviada donde esta (la pregunta SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
es equivalente a esto:
FormsAuth ??= new FormsAuthenticationWrapper();
Algunos lo encuentran más legible y sucinto.