web-dev-qa-db-fra.com

Façons uniques d'utiliser l'opérateur Null Coalescing

Je sais que la manière habituelle d’utiliser l’opérateur de fusion Null en C # consiste à définir des valeurs par défaut.

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

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

Mais à quoi d'autre peut-on utiliser ??? Cela ne semble pas aussi utile que l'opérateur ternaire, mis à part être plus concis et plus facile à lire que:

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

Donc, étant donné que peu de gens connaissent même l'opérateur de coalescence nul ...

  • Avez-vous utilisé ?? pour autre chose?

  • Est-ce que ?? est nécessaire, ou devriez-vous simplement utiliser l'opérateur ternaire (que la plupart des utilisateurs connaissent déjà)

148
Armstrongest

Eh bien, tout d’abord, il est beaucoup plus facile de chaîner que le ternaire standard:

string anybody = parm1 ?? localDefault ?? globalDefault;

vs.

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

Cela fonctionne aussi bien si l'objet null-possible n'est pas une variable:

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

contre. 

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];
197
James Curran

Je l'ai utilisé comme une ligne à chargement paresseux:

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

Lisible? Décider vous-même.

172
Cristian Libardo

Je l'ai trouvé utile de deux manières "légèrement étranges":

  • En guise d'alternative pour avoir un paramètre out lors de l'écriture de routines TryParse (c'est-à-dire, renvoyer la valeur null si l'analyse échoue)
  • En tant que représentation "ne sait pas" pour les comparaisons

Ce dernier a besoin d'un peu plus d'informations. Généralement, lorsque vous créez une comparaison avec plusieurs éléments, vous devez voir si la première partie de la comparaison (par exemple, l'âge) donne une réponse définitive, puis la partie suivante (par exemple, nom) uniquement si la première partie ne vous aide pas. L'utilisation de l'opérateur de fusion nul signifie que vous pouvez écrire des comparaisons assez simples (que ce soit pour l'ordre ou l'égalité). Par exemple, en utilisant quelques classes d’aide dans 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;
}

Certes, j'ai maintenant ProjectionComparer dans MiscUtil, avec quelques extensions, qui rendent ce genre de choses encore plus facile - mais ça reste très chouette.

La même chose peut être faite pour vérifier l’égalité des références (ou la nullité) au début de la mise en œuvre d’Equal.

51
Jon Skeet

Un autre avantage est que l'opérateur ternaire nécessite une double évaluation ou une variable temporaire.

Considérez ceci, par exemple:

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

tandis qu'avec l'opérateur ternaire, il vous reste soit:

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

qui appelle deux fois MyMethod, ou:

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

Quoi qu'il en soit, l'opérateur de coalescence nul est plus propre et, je suppose, plus efficace.

32
Mario Cossi

Une autre chose à considérer est que l'opérateur de coalesce n'appelle pas deux fois la méthode get d'une propriété, comme le fait le ternaire.

Il existe donc des scénarios dans lesquels vous ne devriez pas utiliser ternary, par exemple:

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

Si tu utilises: 

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

le getter sera appelé deux fois et la variable count sera égale à 2, et si vous utilisez:

var b = a.Prop ?? 0

la variable count sera égale à 1, comme il se doit.

20
Fabio Lima

Le principal avantage que je trouve pour l'opérateur ?? est que vous pouvez facilement convertir les types de valeur nullable en types non nullables:

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

J'utilise fréquemment ceci dans les requêtes 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?
14
Ryan

J'ai utilisé ?? dans mon implémentation de IDataErrorInfo:

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

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

Si une propriété individuelle est dans un état "erreur", je reçois cette erreur, sinon je reçois null Fonctionne vraiment bien.

9
Matt Hamilton

Vous pouvez utiliser l'opérateur de coalescence nulle pour le rendre plus propre afin de gérer le cas où un paramètre facultatif n'est pas défini:

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...
7
Niall Connaughton

Est ?? nécessaire, ou devriez-vous simplement utiliser l'opérateur ternaire (que la plupart connaissent bien)

En fait, selon mon expérience, trop peu de gens connaissent l'opérateur ternaire (ou plus exactement l'opérateur conditionnel ; ?: est "ternaire" dans le même sens que || est binaire ou + est unaire ou binaire; il s’agit cependant du seul opérateur ternaire dans de nombreuses langues), donc au moins dans cet échantillon limité, votre déclaration échoue là.

En outre, comme mentionné précédemment, il existe une situation majeure dans laquelle l’opérateur de coalescence nulle est très utile, c’est-à-dire chaque fois que l’expression à évaluer produit des effets secondaires. Dans ce cas, vous ne pouvez pas utiliser l'opérateur conditionnel sans (a) l'introduction d'une variable temporaire ou (b) la modification de la logique réelle de l'application. (b) n’est clairement approprié en aucune circonstance, et bien qu’il s’agisse d’une préférence personnelle, je n’aime pas encombrer le champ de la déclaration avec de nombreuses variables superflues, même de courte durée, de sorte que (a) existe aussi dans cette scénario particulier.

Bien sûr, si vous devez effectuer plusieurs vérifications sur le résultat, l'opérateur conditionnel ou un ensemble de blocs if sont probablement l'outil du travail. Mais pour "si cela est nul, utilisez-le, sinon utilisez-le", l'opérateur de coalescence nul ?? est parfait.

5
a CVn

J'aime utiliser l'opérateur null coalesce pour charger paresseux certaines propriétés.

Un exemple très simple (et artificiel) juste pour illustrer mon propos:

public class StackOverflow
{
    private IEnumerable<string> _definitions;
    public IEnumerable<string> Definitions
    {
        get
        {
            return _definitions ?? (
                _definitions = new List<string>
                {
                    "definition 1",
                    "definition 2",
                    "definition 3"
                }
            );
        }
    } 
}
5
mlnyc

Seul problème, l'opérateur null-coalesce ne détecte pas les chaînes vides. 


c'est à dire.

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

string result2 = null ?? "coalesced!";

SORTIE:

result1 = ""

result2 = coalesced!

Je suis en train de chercher à passer outre le ?? opérateur pour contourner ce problème. Il serait certainement utile d’inclure cela dans le cadre.

Pensées?

4
whatispunk

Une chose que j’ai beaucoup fait récemment consiste à utiliser la fusion nulle pour les sauvegardes à as. Par exemple:

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

Console.WriteLine(i); // Prints 4

C'est aussi utile pour sauvegarder de longues chaînes de ?. qui pourraient toutes échouer

int result = MyObj?.Prop?.Foo?.Val ?? 4;
string other = (MyObj?.Prop?.Foo?.Name as string)?.ToLower() ?? "not there";
4
Blue0500

Est ?? nécessaire, ou devriez-vous simplement utiliser l'opérateur ternaire (que la plupart connaissent bien)

Vous devriez utiliser ce qui exprime le mieux votre intention. Puisqu'il y a est un opérateur de fusion nul, utilisez-le .

D'autre part, étant donné qu'il est tellement spécialisé, je ne pense pas qu'il ait d'autres utilisations. J'aurais préféré une surcharge appropriée de l'opérateur ||, comme le font les autres langues. Ce serait plus parcimonieux dans la conception du langage. Enfin bon …

3
Konrad Rudolph

Cool! Comptez sur moi comme quelqu'un qui ne connaissait pas l'opérateur de coalescence nul - c'est très chouette.

Je trouve cela beaucoup plus facile à lire que l'opérateur ternaire.

La première chose qui me vienne à l’esprit, c’est de garder tous mes paramètres par défaut au même endroit.

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
HanClinto

C'est un cas d'utilisation étrange, mais j'avais une méthode dans laquelle un objet IDisposable est potentiellement passé en tant qu'argument (et donc éliminé par le parent), mais peut également être null (et devrait donc être créé et éliminé dans la méthode locale)

Pour l'utiliser, le code ressemblait soit à

Channel channel;
Authentication authentication;

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

Mais avec une fusion nulle devient beaucoup plus propre

using (entities ?? Entities.GetEntities())
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}
1
PaulG

Opérateur de coalescence nulle

Cet opérateur vérifie si la variable est null et renvoie la valeur en regard de l'opérateur "??" sinon donne la valeur enregistrée dans la variable.

Ex: -1

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

o/p: ATHUL

Ex: -2 

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

o/p: le nom est null

0
Athul Nalupurakkal