2009-02-17 5 views
5

Dans les langages fonctionnels, il existe souvent une monade Maybe qui vous permet d'enchaîner plusieurs appels sur un objet et de renvoyer l'expression entière None/null si une partie de la chaîne n'évalue rien, plutôt que les NullReferenceException typiques que vous obtiendriez C# en enchaînant les appels où un objet pourrait être nul. Cela peut être implémenté de manière triviale en écrivant un Maybe<T> avec des méthodes d'extension pour permettre un comportement similaire en C# en utilisant des requêtes compréhensibles, ce qui peut être utile lors du traitement de XML avec des éléments/attributs facultatifs, par ex.Est-ce qu'un opérateur conditionnel de référence est une bonne chose en C#?

var val = from foo in doc.Elements("foo").FirstOrDefault().ToMaybe() 
      from bar in foo.Attribute("bar").ToMaybe() 
      select bar.Value; 

Mais cette syntaxe est un peu maladroit et peu intuitive que les gens sont habitués à traiter avec des séquences en Linq plutôt que des éléments simples, et il vous laisse avec un Maybe<T> plutôt qu'un T à la fin. Est-ce qu'un opérateur conditionnel de référence (par exemple ..) être suffisamment utile pour en faire la langue? par exemple.

var val = doc.Elements("foo").FirstOrDefault()..Attribute("bar")..Value; 

Le de référence conditionnelle se développerait à quelque chose comme:

object val; 
var foo = doc.Elements("foo").FirstOrDefault(); 
if (foo != null) 
{ 
    var bar = foo.Attribute("bar"); 
    if (bar != null) 
    { 
     val = bar.Value; 
    } 
    else 
    { 
     val = null; 
    } 
} 

Je peux voir que cela pourrait conduire à des abus terribles comme l'utilisation .. partout pour éviter une NullReferenceException, mais d'autre part lorsqu'il est utilisé correctement, il pourrait être très utile dans un certain nombre de situations. Pensées?

+0

J'aime l'idée, beaucoup. Je suggère fortement d'utiliser quelque chose d'autre. Peut-être '??.'. En tout cas, quelque chose qui n'est pas une faute de frappe commune loin de '.'. –

Répondre

1

Chaînage plusieurs appels sur un objet me fait craindre des violations du Law of Demeter. Ainsi, je suis sceptique que cette fonctionnalité est une bonne idée, au moins en termes de résolution du problème spécifique que vous utilisez comme exemple.

+0

J'ai spécifiquement choisi l'exemple XML pour montrer une situation où il est virtuellement impossible de ne pas enfreindre cette loi en faisant quoi que ce soit de réellement utile, car XML est une arborescence bien documentée où cette loi ne s'applique pas vraiment. –

+0

Le problème avec la Loi de Déméter est que quelqu'un l'a appelé "Loi de Déméter" plutôt que "Guide de Demeter" qui est ce que c'est. Les lignes directrices sont là pour nous guider, mais elles ne devraient pas faire obstacle à une bonne idée. –

+0

Je réponds que c'est ce que xpath est pour mais je peux voir où une chaîne pure serait considérée plus laide par certains. Cela dit, la plupart du temps ce n'est pas quelque chose que vous voulez faire. – Brian

0

Il est une idée intéressante qui pourrait être réalisée avec une méthode d'extension. Quelque chose comme ça, par exemple (note, il suffit par exemple - je suis sûr qu'il peut être affiné):

public static IEnumerable<T> Maybe<T>(this IEnumerable<T> lhs, Func<IEnumerable<T>, T> rhs) 
{ 
    if (lhs != null) 
    { 
    return rhs(lhs); 
    } 

    return lhs; 
} 
0

Je soupçonne une combinaison de NULLABLE et des méthodes d'extension permettrait à une partie importante de ce à b atteint.

Cela limiterait T aux types de valeur bien sûr.

(TBH Je préférerais voir le soutien de tuple dans le langauge et éliminer les paramètres out, comme F # fait.)

Code Vous pouvez être simplifié, val null définir et vous éliminer les branches d'autre.

-2

Je peux voir l'utilité potentielle, mais autre qu'un léger impact sur les performances si les éléments sont souvent nuls, pourquoi ne pas simplement entourer le bloc de code avec un bloc try..catch pour une exception NullReferenceException?

+0

Le problème avec l'utilisation d'un try/catch est qu'il vous jette hors de la requête. Avec une opération qui gère null, la requête peut terminer et donner un résultat valide, ce qui pourrait être très utile si vous avez plusieurs expressions dans votre requête. –

+0

Exceptions pour le contrôle de flux n'est pratiquement jamais une bonne idée ... Je ne vais pas aller dans pourquoi ici; il y a beaucoup d'informations sur ce site et sur Internet en général à ce sujet. –

+0

Ahh, j'étais sous l'impression qu'aucun résultat valide ne serait obtenu si l'une des parties de la requête renvoyait null - cela ne générerait tout simplement pas d'erreur. Quant à l'utilisation des exceptions pour le contrôle de flux, je suis d'accord - c'est pourquoi j'ai mentionné que les éléments n'étaient pas souvent nuls. –