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à)
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"];
Je l'ai utilisé comme une ligne à chargement paresseux:
public MyClass LazyProp
{
get { return lazyField ?? (lazyField = new MyClass()); }
}
Lisible? Décider vous-même.
Je l'ai trouvé utile de deux manières "légèrement étranges":
out
lors de l'écriture de routines TryParse
(c'est-à-dire, renvoyer la valeur null si l'analyse échoue)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.
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.
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.
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?
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.
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;
...
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.
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"
}
);
}
}
}
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?
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";
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 …
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
}
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);
[...]
}
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