39 votes

pourquoi préférons-nous? à ?? opérateur en c #?

J'ai récemment trouvé que nous pouvons utiliser ?? opérateur de vérifier les valeurs null. Veuillez vérifier les ci-dessous des exemples de code:

   var res = data ?? new data();

C'est exactement la même

   var res = (data==null) ? new data() : data ;

J'ai vérifié l'ensemble de mon projet de référentiel source et certains d'autres projets open source. Et ce ?? opérateur jamais été utilisé.

Je me demandais est-il une raison derrière tout cela, comme des problèmes de performances ou quelque chose?

EDIT:

Je viens de mettre à jour mon exemple de code sur la base des observations de récursive & Anton. Son, une erreur dans l'insouciance. :(

58voto

Bob Points 34449

Le nul de fusionner opérateur est beaucoup plus clair lors de la vérification de null, c'est son but principal. Il peut également être enchaînés.

object a = null;
object b = null;
object c = new object();
object d = a ?? b ?? c; //d == c.

Alors que l'opérateur est limitée à la valeur null de la vérification, l'opérateur ternaire est pas. Par exemple

bool isQuestion = true;
string question = isQuestion ? "Yes" : "No";

Je pense que les gens ne sont pas conscients de la valeur null fusionnent opérateur afin qu'ils utiliser l'opérateur ternaire à la place. Ternaire existait avant C# dans la plupart des C style de langues, de sorte si vous ne savez pas C# à l'intérieur et à l'extérieur et/ou que vous avez programmé dans une autre langue, ternaire est un choix naturel. Si vous êtes à la vérification de la valeur null si, utilisez la valeur null fusionnent opérateur, il est conçu pour cela, et IL est légèrement optimisé (comparer ?? pour un if then else).

Voici un exemple de comparaison de l'utilisation de chaque

object a = null;
object b = null;
object c = null;

object nullCoalesce = a ?? b ?? c;

object ternary = a != null ? a : b != null ? b : c;

object ifThenElse;

if (a != null)
	ifThenElse = a;
else if (b != null)
	ifThenElse = b;
else if (c != null)
	ifThenElse = c;

Tout d'abord, il suffit de regarder la syntaxe pour les nuls fusionnent, c'est plus clair. Ternaire est vraiment déroutant. Regardons maintenant le IL

Null Fusionnent Seulement

.entrypoint
.maxstack 2
.locals init (
    [0] object a,
    [1] object b,
    [2] object c,
    [3] object nullCoalesce)
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: dup 
L_000c: brtrue.s L_0015
L_000e: pop 
L_000f: ldloc.1 
L_0010: dup 
L_0011: brtrue.s L_0015
L_0013: pop 
L_0014: ldloc.2 
L_0015: stloc.3 
L_0016: ldloc.3 
L_0017: call void [mscorlib]System.Console::WriteLine(object)
L_001c: ret

Ternaire Seulement

.entrypoint
.maxstack 2
.locals init (
    [0] object a,
    [1] object b,
    [2] object c,
    [3] object ternary)
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: brtrue.s L_0016
L_000d: ldloc.1 
L_000e: brtrue.s L_0013
L_0010: ldloc.2 
L_0011: br.s L_0017
L_0013: ldloc.1 
L_0014: br.s L_0017
L_0016: ldloc.0 
L_0017: stloc.3 
L_0018: ldloc.3 
L_0019: call void [mscorlib]System.Console::WriteLine(object)
L_001e: ret

Si Alors Sinon Seulement

.entrypoint
.maxstack 1
.locals init (
    [0] object a,
    [1] object b,
    [2] object c,
    [3] object ifThenElse)
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: brfalse.s L_0011
L_000d: ldloc.0 
L_000e: stloc.3 
L_000f: br.s L_001a
L_0011: ldloc.1 
L_0012: brfalse.s L_0018
L_0014: ldloc.1 
L_0015: stloc.3 
L_0016: br.s L_001a
L_0018: ldloc.2 
L_0019: stloc.3 
L_001a: ldloc.3 
L_001b: call void [mscorlib]System.Console::WriteLine(object)
L_0020: ret

IL n'est pas un de mes points forts, peut-être que quelqu'un peut éditer ma réponse et d'étendre sur elle. Je vais expliquer ma théorie, mais je préfère ne pas confondre moi et pour les autres. Le nombre de LOC est similaire pour tous les trois, mais pas tous, IL exploitants de prendre la même longueur de temps à s'exécuter.

12voto

Rytmis Points 15848

L' ?? opérateur (aussi connu comme le null-coalescence de l'opérateur) est moins connu que l'opérateur ternaire, comme il a fait ses débuts avec .NET 2.0 et les Types Nullables. Raisons pour ne pas l'utiliser probablement inclure commence pas au courant qu'il existe, ou d'être plus familier avec l'opérateur ternaire.

Cela dit, la vérification de la valeur null n'est pas la seule chose que l'opérateur ternaire est bon pour, donc ce n'est pas un remplacement pour elle en tant que telle, comme une meilleure alternative pour des besoins très particuliers. :)

6voto

Binoj Antony Points 7519

Une raison à laquelle je peux penser est que cet opérateur a été introduit dans .NET 2.0, donc le code pour .NET 1.1 ne peut pas l'avoir.

Je suis d'accord avec vous, nous devrions l'utiliser plus souvent.

lien ref

4voto

Matthew Whited Points 12255

Basé sur la réponse de Bob

 public object nullCoalesce(object a, object b, object c)
{
    return a ?? b ?? c;
}
public object ternary(object a, object b, object c)
{
    return a != null ? a : b != null ? b : c;
}
public object ifThenElse(object a, object b, object c)
{
    if (a != null)
        return a;
    else if (b != null)
        return b;
    else
        return c;
}
 

... c'est l'IL des versions de version ...

 .method public hidebysig instance object nullCoalesce(
    object a, 
    object b, 
    object c) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: dup 
    L_0002: brtrue.s L_000b
    L_0004: pop 
    L_0005: ldarg.2 
    L_0006: dup 
    L_0007: brtrue.s L_000b
    L_0009: pop 
    L_000a: ldarg.3 
    L_000b: ret 
}

.method public hidebysig instance object ternary(
    object a, 
    object b, 
    object c) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: brtrue.s L_000a
    L_0003: ldarg.2 
    L_0004: brtrue.s L_0008
    L_0006: ldarg.3 
    L_0007: ret 
    L_0008: ldarg.2 
    L_0009: ret 
    L_000a: ldarg.1 
    L_000b: ret 
}

.method public hidebysig instance object ifThenElse(
    object a, 
    object b, 
    object c) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: brfalse.s L_0005
    L_0003: ldarg.1 
    L_0004: ret 
    L_0005: ldarg.2 
    L_0006: brfalse.s L_000a
    L_0008: ldarg.2 
    L_0009: ret 
    L_000a: ldarg.3 
    L_000b: ret 
}
 

1voto

Karel Bílek Points 5237

Je pense que c'est juste une habitude dans d'autres langues. AUTANT QUE JE SACHE, ?? L'opérateur n'est utilisé dans aucune autre langue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X