web-dev-qa-db-fra.com

Y a-t-il un "opposé" à l'opérateur de coalescence nul? (… Dans n'importe quelle langue?)

la coalescence nulle se traduit approximativement par return x, unless it is null, in which case return y

J'ai souvent besoin de return null if x is null, otherwise return x.y

Je peux utiliser return x == null ? null : x.y;

Pas mal, mais que null au milieu me dérange toujours - cela semble superflu. Je préfère quelque chose comme return x :: x.y;, Où ce qui suit le :: N'est évalué que si ce qui le précède n'est pas null.

Je vois cela comme presque un opposé à la coalescence nulle, un peu mélangé avec un contrôle nul en ligne, mais je suis [presque] certain qu'il n'y a pas un tel opérateur en C #.

Y a-t-il d'autres langues qui ont un tel opérateur? Si oui, comment s'appelle-t-il?

(Je sais que je peux écrire une méthode pour cela en C #; j'utilise return NullOrValue.of(x, () => x.y);, mais si vous avez quelque chose de mieux, j'aimerais voir ça aussi.)

91
Jay

Il y a l'opérateur de déréférencement sans danger (?.) Dans Groovy ... Je pense que c'est ce que vous recherchez.

(Il est également appelé opérateur de navigation sécurisé .)

Par exemple:

homePostcode = person?.homeAddress?.postcode

Cela donnera null si person, person.homeAddress ou person.homeAddress.postcode est nul.

(Ceci est maintenant disponible dans C # 6. mais pas dans les versions antérieures)

62
Jon Skeet

Nous avons envisagé d'ajouter?. à C # 4. Il n'a pas fait la coupe; c'est une fonctionnalité "Nice to have", pas une fonctionnalité "gotta have". Nous l'examinerons à nouveau pour les futures versions hypothétiques de la langue, mais je ne retiendrais pas mon souffle en attendant si j'étais vous. Il est peu probable que cela devienne plus crucial au fil du temps. :-)

36
Eric Lippert

Si vous avez un type spécial de logique booléenne de court-circuit, vous pouvez le faire (exemple javascript):

return x && x.y;

Si x est nul, il n'évaluera pas x.y.

16
Eric

Cela me semblait juste d'ajouter cela comme réponse.

Je suppose que la raison pour laquelle il n'y a pas une telle chose en C # est que, contrairement à l'opérateur de coalescence (qui n'est valide que pour les types de référence), l'opération inverse pourrait produire soit une référence soit un type de valeur (c'est-à-dire class x avec membre int y - il serait donc malheureusement inutilisable dans de nombreuses situations.

Je ne dis pas, cependant, que je ne voudrais pas le voir!

Une solution potentielle à ce problème serait pour l'opérateur de soulever automatiquement une expression de type valeur sur le côté droit à une valeur nulle. Mais alors vous avez le problème que x.y où y est un int renvoie en fait un int? ce qui serait pénible.

Une autre solution, probablement meilleure, serait que l'opérateur retourne la valeur par défaut (c'est-à-dire nulle ou nulle) pour le type de droite si l'expression de gauche est nulle. Mais vous rencontrez des problèmes pour distinguer les scénarios dans lesquels un zéro/null a été lu à partir de x.y ou s'il a été fourni par l'opérateur d'accès sécurisé.

7
Andras Zoltan

Delphi a l'opérateur: (plutôt que.), Qui est null-safe.

Ils envisageaient d'ajouter un?. opérateur à C # 4.0 pour faire de même, mais qui a obtenu le bloc de découpage.

En attendant, il y a IfNotNull () quel type de rayures qui démangent. C'est certainement plus grand que?. ou:, mais il vous permet de composer une chaîne d'opérations qui ne fonctionnera pas avec une NullReferenceException si l'un des membres est nul.

6
48klocs

Haskell a fmap, ce qui dans ce cas je pense est équivalent à Data.Maybe.map. Haskell est purement fonctionnel, donc ce que vous cherchez serait

fmap select_y x

Si x est Nothing, cela renvoie Nothing. Si x est Just object, Cela renvoie Just (select_y object). Pas aussi joli que la notation par points, mais étant donné qu'il s'agit d'un langage fonctionnel, les styles sont différents.

3
Norman Ramsey

Dans Haskell, vous pouvez utiliser le >> opérateur:

  • Nothing >> Nothing est Nothing
  • Nothing >> Just 1 est Nothing
  • Just 2 >> Nothing est Nothing
  • Just 2 >> Just 1 est Just 1
3
dave4420

PowerShell vous permet de référencer des propriétés (mais pas d'appeler des méthodes) sur une référence null et il renverra null si l'instance est null. Vous pouvez le faire à n'importe quelle profondeur. J'avais espéré que la fonctionnalité dynamique de C # 4 prendrait en charge cela, mais ce n'est pas le cas.

$x = $null
$result = $x.y  # $result is null

$x = New-Object PSObject
$x | Add-Member NoteProperty y 'test'
$result = $x.y  # $result is 'test'

Ce n'est pas joli mais vous pouvez ajouter une méthode d'extension qui fonctionnera comme vous le décrivez.

public static TResult SafeGet<T, TResult>(this T obj, Func<T, TResult> selector) {
    if (obj == null) { return default(TResult); }
    else { return selector(obj); }
}

var myClass = new MyClass();
var result = myClass.SafeGet(x=>x.SomeProp);
2
Josh
public class ok<T> {
    T s;
    public static implicit operator ok<T>(T s) { return new ok<T> { s = s }; }
    public static implicit operator T(ok<T> _) { return _.s; }

    public static bool operator true(ok<T> _) { return _.s != null; }
    public static bool operator false(ok<T> _) { return _.s == null; }
    public static ok<T> operator &(ok<T> x, ok<T> y) { return y; }
}

J'ai souvent besoin de cette logique pour les chaînes:

using ok = ok<string>;

...

string bob = null;
string joe = "joe";

string name = (ok)bob && bob.ToUpper();   // name == null, no error thrown
string boss = (ok)joe && joe.ToUpper();   // boss == "JOE"
2
J Bryan Price

Créez une instance statique de votre classe quelque part avec toutes les bonnes valeurs par défaut pour les membres.

Par exemple:

z = new Thingy { y=null };

alors au lieu de votre

return x != null ? x.y : null;

tu peux écrire

return (x ?? z).y;
1
Nick

Le soi-disant "opérateur de condition nulle" a été introduit dans C # 6.0 et dans Visual Basic 14.
Dans de nombreuses situations, il peut être utilisé comme l'opposé exact de l'opérateur de coalescence nulle:

int? length = customers?.Length; // null if customers is null   
Customer first = customers?[0];  // null if customers is null  
int? count = customers?[0]?.Orders?.Count();  // null if customers, the first customer, or Orders is null

https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators

1
Jpsy

Ceci est ajouté dans C # vNext (Roslyn propulsé C #, versions avec Visual Studio 2014).

Il est appelé propagation nulle et est répertorié ici comme complet. https://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status

Il est également répertorié ici comme complet: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c

1
Micah Zoltu