Formas únicas de usar el operador coalescente nulo


Sé que la forma estándar de usar el operador coalescente Null en C# es establecer valores predeterminados.

string nobody = null;
string somebody = "Bob Saget";
string anybody = "";

anybody = nobody   ?? "Mr. T"; // returns Mr. T
anybody = somebody ?? "Mr. T"; // returns "Bob Saget"

Pero ¿para qué otra cosa se puede usar ??? No parece tan útil como el operador ternario, aparte de ser más conciso y más fácil de leer que:

nobody = null;
anybody = nobody == null ? "Bob Saget" : nobody; // returns Bob Saget

Así que dado que menos incluso saben acerca de operador coalescente nulo...

  • ¿Has usado ?? para otra cosa?

  • Es ?? necesario, o simplemente debe usar el operador ternario (que la mayoría están familiarizados con)

Author: Omar, 2008-11-10

16 answers

Bueno, en primer lugar, es mucho más fácil encadenar que el ternario estándar:

string anybody = parm1 ?? localDefault ?? globalDefault;

Vs.

string anyboby = (parm1 != null) ? parm1 
               : ((localDefault != null) ? localDefault 
               : globalDefault);

También funciona bien si el objeto null-possible no es una variable:

string anybody = Parameters["Name"] 
              ?? Settings["Name"] 
              ?? GlobalSetting["Name"];

Vs.

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];
 191
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-10 18:31:04

Lo he utilizado como una carga perezosa one-liner:

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

Legible? Decide por ti mismo.

 170
Author: Cristian Libardo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-10 18:25:55

Lo he encontrado útil de dos maneras "ligeramente extrañas":

  • Como alternativa para tener un parámetro out al escribir rutinas TryParse (es decir, devolver el valor null si el análisis falla)
  • Como representación de" no sé " para comparaciones

Este último necesita un poco más de información. Por lo general, cuando se crea una comparación con varios elementos, es necesario ver si la primera parte de la comparación (por ejemplo, edad) da una respuesta definitiva, a continuación, la siguiente parte (por ejemplo, nombre) solo si la primera parte no ayudó. Usar el operador coalescente null significa que puede escribir comparaciones bastante simples (ya sea para ordenar o igualar). Por ejemplo, usando un par de clases auxiliares en MiscUtil :

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

Es cierto que ahora tengo ProjectionComparer en MiscUtil, junto con algunas extensiones, que hacen que este tipo de cosas sean aún más fáciles, pero todavía está limpio.

Lo mismo se puede hacer para comprobar la igualdad de referencia (o nulidad) al comienzo de implementando Iguales.

 50
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-10 19:30:56

Otra ventaja es que el operador ternario requiere una doble evaluación o una variable temporal.

Considere esto, por ejemplo:

string result = MyMethod() ?? "default value";

Mientras que con el operador ternario se queda con cualquiera de los dos:

string result = (MyMethod () != null ? MyMethod () : "default value");

Que llama a myMethod dos veces, o:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

De cualquier manera, el operador coalescente nulo es más limpio y, supongo, más eficiente.

 31
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-19 21:30:48

Otra cosa a considerar es que el operador coalesce no llama al método get de una propiedad dos veces, como lo hace el ternario.

Así que hay escenarios en los que no deberías usar ternary, por ejemplo:

public class A
{
    var count = 0;
    private int? _prop = null;
    public int? Prop
    {
        get 
        {
            ++count;
            return _prop
        }
        set
        {
            _prop = value;
        }
    }
}

Si usa:

var a = new A();
var b = a.Prop == null ? 0 : a.Prop;

El getter será llamado dos veces y la variable count será igual a 2, y si usas:

var b = a.Prop ?? 0

La variable count será igual a 1, como debería ser.

 17
Author: Fabio Lima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-17 13:52:03

La mayor ventaja que encuentro para el operador ?? es que puede convertir fácilmente tipos de valores nullables a tipos no nullables:

int? test = null;
var result = test ?? 0; // result is int, not int?

Con frecuencia uso esto en consultas Linq:

Dictionary<int, int?> PurchaseQuantities;
// PurchaseQuantities populated via ASP .NET MVC form.
var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);
// totalPurchased is int, not int?
 13
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-27 22:25:08

He usado ?? en mi implementación de IDataErrorInfo:

public string Error
{
    get
    {
        return this["Name"] ?? this["Address"] ?? this["Phone"];
    }
}

public string this[string columnName]
{
    get { ... }
}

Si alguna propiedad individual está en un estado de "error" obtengo ese error, de lo contrario obtengo null. Funciona muy bien.

 9
Author: Matt Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-11 09:56:36

Puede usar el operador coalescente null para que sea un poco más limpio para manejar el caso donde no se establece un parámetro opcional:

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...
 6
Author: Niall Connaughton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-01 07:59:53

Es ?? necesario, o solo debe usar el operador ternario (con el que la mayoría está familiarizada)

En realidad, mi experiencia es que muy pocas personas están familiarizadas con el operador ternario (o más correctamente, el operador condicional ; ?: es "ternario" en el mismo sentido que || es binario o + es unario o binario; sin embargo, sucede que es el único operador ternario en muchos idiomas), por lo que al menos en esa muestra limitada, su declaración falla ahí.

También, como se mencionó anteriormente, hay una situación importante cuando el operador coalescente nulo es muy útil, y es cuando la expresión a evaluar tiene algún efecto secundario. En ese caso, no puede usar el operador condicional sin (a) introducir una variable temporal, o (b) cambiar la lógica real de la aplicación. (b) claramente no es apropiado en ninguna circunstancia, y aunque es una preferencia personal, no me gusta el desorden subir el ámbito de la declaración con un montón de variables extrañas, incluso si de corta duración, por lo que (a) está fuera demasiado en ese escenario en particular.

Por supuesto, si necesita hacer varias comprobaciones en el resultado, el operador condicional, o un conjunto de bloques if, son probablemente la herramienta para el trabajo. Pero para "if this is null, use that, otherwise use it", el operador de coalescencia null ?? es perfecto.

 5
Author: Michael Kjörling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-16 18:43:58

El único problema es que el operador null-coalesce no detecta cadenas vacías.


Es decir,

string result1 = string.empty ?? "dead code!";

string result2 = null ?? "coalesced!";

SALIDA:

result1 = ""

result2 = coalesced!

Actualmente estoy buscando sobreescribir el ?? operadora para solucionar esto. Seguramente sería útil tener esto incorporado en el Marco.

Pensamientos?

 4
Author: Kevin Panko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-03 18:11:22

Me gusta usar el operador null coalesce para cargar perezosamente ciertas propiedades.

Un ejemplo muy simple (y artificial) solo para ilustrar mi punto:

public class StackOverflow
{
    private IEnumerable<string> _definitions;
    public IEnumerable<string> Definitions
    {
        get
        {
            return _definitions ?? (
                _definitions = new List<string>
                {
                    "definition 1",
                    "definition 2",
                    "definition 3"
                }
            );
        }
    } 
}
 4
Author: mlnyc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-19 14:51:43

Es ?? necesario, o solo debe usar el operador ternario (con el que la mayoría está familiarizada)

Debes usar lo que mejor expresa tu intención. Dado que existe un operador de coalescencia nulo, úselo.

Por otro lado, como es tan especializado, no creo que tenga otros usos. Hubiera preferido una sobrecarga apropiada del operador ||, como lo hacen otros lenguajes. Esto sería más parsimonioso en el diseño del lenguaje. Pero bueno ...

 3
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-10 18:24:38

¡Genial! Cuéntame como alguien que no sabía sobre el operador coalescente nulo that eso es bastante ingenioso.

Lo encuentro mucho más fácil de leer que el operador ternario.

El primer lugar que me viene a la mente donde podría usarlo es mantener todos mis parámetros predeterminados en un solo lugar.

public void someMethod( object parm2, ArrayList parm3 )
{ 
  someMethod( null, parm2, parm3 );
}
public void someMethod( string parm1, ArrayList parm3 )
{
  someMethod( parm1, null, parm3 );
}
public void someMethod( string parm1, object parm2, )
{
  someMethod( parm1, parm2, null );
}
public void someMethod( string parm1 )
{
  someMethod( parm1, null, null );
}
public void someMethod( object parm2 )
{
  someMethod( null, parm2, null );
}
public void someMethod( ArrayList parm3 )
{
  someMethod( null, null, parm3 );
}
public void someMethod( string parm1, object parm2, ArrayList parm3 )
{
  // Set your default parameters here rather than scattered through the above function overloads
  parm1 = parm1 ?? "Default User Name";
  parm2 = parm2 ?? GetCurrentUserObj();
  parm3 = parm3 ?? DefaultCustomerList;

  // Do the rest of the stuff here
}
 3
Author: HanClinto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-10 18:31:37

Una cosa que he estado haciendo mucho últimamente es usar coalescencia nula para copias de seguridad de as. Por ejemplo:

object boxed = 4;
int i = (boxed as int?) ?? 99;

Console.WriteLine(i); // Prints 4

También es útil para respaldar cadenas largas de ?. que podrían fallar

int result = MyObj?.Prop?.Foo?.Val ?? 4;
string other = (MyObj?.Prop?.Foo?.Name as string)?.ToLower() ?? "not there";
 3
Author: Blue0500,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-29 14:09:47

Un caso de uso un poco raro, pero tenía un método donde un objeto IDisposable es potencialmente pasado como un arg (y por lo tanto eliminado por el padre), pero también podría ser nulo (y por lo tanto debe ser creado y dispuesto en el método local)

Para usarlo, el código parecía

Channel channel;
Authentication authentication;

if (entities == null)
{
    using (entities = Entities.GetEntities())
    {
        channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
        [...]
    }
}
else
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

Pero con una fusión nula se vuelve mucho más ordenada

using (entities ?? Entities.GetEntities())
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}
 0
Author: PaulG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-19 18:23:02

Null-Coalescing Operator

Este operador comprueba la variable, si es null, devuelve el valor junto al "??"operador else dar el valor guardado en la variable.

Eg: -1

var name=”ATHUL”;
var result =name ?? “The name is null”
Console.WriteLine(result);

O/p : ATHUL

Eg: -2

var name=null;
var result =name ?? “The name is null”
Console.WriteLine(result);

O / p: El nombre es null

 0
Author: Athul Nalupurakkal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-20 07:24:14