58 votes

Meilleure syntaxe pour a = (x == null) ? null : x.func()

Question de base : j'ai plusieurs lignes de code qui ressemblent à quelque chose comme ça :

var a = (long_expression == null) ? null : long_expression.Method();

Des lignes similaires se répètent souvent dans cette fonction. long_expression est différent à chaque fois. J'essaie de trouver un moyen d'éviter de répéter long_expression mais en gardant cette compacité . Quelque chose comme le contraire de operator ?? . Pour le moment, j'envisage de céder et de le mettre sur plusieurs lignes, par exemple :

var temp = long_expression;
var a = (temp == null) ? null : temp.Method();

Mais je suis curieux de savoir s'il existe une syntaxe intelligente que je ne connais pas et qui permettrait d'être plus concis.

77voto

Jon Skeet Points 692016

Eh bien, vous pourrait utiliser une méthode d'extension comme celle-ci :

public static TResult NullOr<TSource, TResult>(this TSource source,
    Func<TSource, TResult> func) where TSource : class where TResult : class
{
    return source == null ? null : func(source);
}

Ensuite :

var a = some_long_expression.NullOr(x => x.Method());

Ou (en fonction de votre version de C#)

var a = some_long_expression.NullOr(Foo.Method);

donde Foo est le type de some_long_expression .

Je ne pense pas que je serait faire ça cependant. J'utiliserais simplement la version à deux lignes. C'est plus simple et moins intelligent - et si "intelligent" est amusant pour Stack Overflow, ce n'est généralement pas une bonne idée pour du vrai code.

49voto

David B Points 53123

J'ai trouvé cette réponse perspicace.

En effectuant cette mission, vous propagez la nullité plus profondément dans le système. Vous devrez réécrire votre condition de traitement des nuls (et encore et encore) pour gérer ces propagations.

Au lieu de laisser l'exécution se poursuivre avec des nullités, remplacez la nullité par une meilleure représentation (citation du lien).

  1. Si le null représente une collection vide, utilisez une collection vide.
  2. Si le null représente un cas exceptionnel, lancez une exception.
  3. Si le null représente une valeur accidentellement non initialisée, il faut l'initialiser explicitement.
  4. Si le null représente une valeur légitime, testez-le - ou mieux encore, utilisez un NullObject qui exécute une opération null.

En particulier, le remplacement d'une référence de collection nulle par une collection vide m'a épargné de nombreux tests nuls.

5voto

PointedEars Points 4933
var x = "";

/* try null instead */
string long_expression = "foo";

var a = ((x = long_expression) == null) ? null : x.ToUpper();

/* writes "FOO" (or nothing) followed by newline */
Console.WriteLine(a);

Le type de la valeur d'initialisation de x doit être compatible avec le type de long_expression (ici : string ). Fonctionne avec le Mono Compilateur C#, version 2.10.8.1 (du paquet Debian mono-gmcs=2.10.8.1-4).

5voto

Ken Beckett Points 577

Je pense que le langage C# pourrait vraiment utiliser un nouvel opérateur pour ce genre de logique - c'est assez courant, et un opérateur simplifierait d'innombrables lignes de code.

Nous avons besoin de quelque chose qui ressemble à l'opérateur " ??" ou "if null then", mais qui fonctionne comme un opérateur point spécial '.' avec une condition "if not null". Pour " ??", le premier " ?" est comme la partie "if" du "if-then" "? :", et le second " ?" représente "null" comme pour les types nullables. Je pense que nous avons besoin d'un opérateur ". ?" qui fonctionne comme '.', sauf qu'il évalue simplement à null si l'expression de gauche est null au lieu de lancer une exception. Je suppose qu'il s'agirait d'un opérateur "dot not null" (OK, peut-être que ". !?" serait plus logique, mais n'allons pas là).

Ainsi, votre exemple si courant pourrait perdre le nom redondant du symbole comme ceci :

var a = long_expression.?Method();

Il existe une tonne de code C# avec des contrôles de nullité imbriqués qui en bénéficieraient grandement. Pensez juste à ce que ce serait bien si cela :

if (localObject != null)
{
    if (localObject.ChildObject != null)
    {
        if (localObject.ChildObject.ChildObject != null)
            localObject.ChildObject.ChildObject.DoSomething();
    }
}

pourrait devenir juste :

localObject.?ChildObject.?ChildObject.?DoSomething();

Il y a également une tonne de code où les contrôles de nullité qui devraient être présents sont absents, ce qui entraîne des erreurs d'exécution occasionnelles. Ainsi, l'utilisation par défaut du nouvel opérateur '.?' éliminerait ces problèmes... Il est peut-être regrettable que nous ne puissions pas inverser le comportement de '.' et '.?' à ce stade, de sorte que seul le nouvel opérateur '.?' lève une exception si le côté gauche est nul - ce serait la façon plus propre et plus logique de procéder, mais les changements brutaux sont très mauvais. Bien que l'on puisse argumenter que ce changement particulier serait susceptible de résoudre beaucoup de problèmes cachés, et peu susceptible de casser quoi que ce soit (seulement le code qui s'attend à ce qu'une exception null ref soit levée). Oh, eh bien... on peut toujours rêver...

Le seul inconvénient de la vérification de la nullité est vraiment le léger impact sur les performances, ce qui est certainement la raison pour laquelle '.' ne vérifie pas la nullité. Mais, je pense vraiment que la possibilité d'utiliser simplement '.?' lorsque vous vous souciez des performances (et que vous savez que le côté gauche ne sera jamais nul) aurait été la meilleure solution.

Dans le même ordre d'idées, il aurait été beaucoup plus agréable que les instructions "foreach" vérifient et ignorent une collection nulle. Plus besoin d'envelopper la plupart des instructions 'foreach' avec "if (collection != null)", ou pire, de développer l'habitude commune de toujours utiliser des collections vides au lieu de null ... ce qui est bien dans certains cas, mais un problème de performance encore pire que la vérification de null quand cela est fait dans des arbres d'objets complexes où la majorité des collections sont vides (ce que j'ai beaucoup vu). Je pense que la bonne intention de ne pas avoir de vérification de null dans 'foreach' pour fournir de meilleures performances s'est retournée contre nous dans la majorité des cas.

Anders, il n'est jamais trop tard pour effectuer de tels changements, et ajouter un commutateur de compilateur pour les activer !

1voto

Sahuagin Points 3209

Vous pouvez écrire une méthode d'extension pour tout type d'expression longue évaluée :

public static object DoMethod(this MyType pLongExpression)
{
   return pLongExpression == null ? null : pLongExpression.Method();
}

Il sera possible de l'appeler sur n'importe quel MyType même si cette référence est null .

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