2010-10-22 24 views
0

Est-il possible d'avoir une implémentation DynamicObject qui peut être appelée en chaîne en gardant une référence nulle à la fin si une référence nulle est trouvée dans le chemin, sans aucune exception?appel trygetmember sur des références nulles chaînées

a.b.c.e 

par exemple: si un est nul alors a.b.c.e est nulle, ou si c est c.e nulle est nulle, etc.?

Très semblable à la monade Maybe de Haskell.

+0

ressemble "a.b.c.e" mais agit comme un "null == null: a.b == null null: a.b.c == null null: a.b.c.d"? – xcud

+0

@xcud: oui exactement mais je ne veux pas écrire tout cela ==? nulls: ... –

Répondre

1

Vous pouvez faire quelque chose comme ça, mais pas pour l'objet le plus à l'extérieur, c'est-à-dire si a est nul, vous ne pouvez pas accéder à a.b.

Vous pouvez créer une instance vide de la classe A, qui renvoie des instances vides pour toutes ses propriétés. Puis a.b retournera une instance vide de B, qui pour la propriété c retournera une instance vide de C, qui pour la propriété e retournera une instance vide de E.

Vous n'obtenir une valeur nulle, mais vous obtiendrez une instance vide, que vous pouvez vérifier avec:

E e = a.b.c.e; 
if (e != E.Empty) { ... } 

Si l'une des propriétés le long du chemin retourne une instance vide, le résultat final être E.Empty.

public class A { 

    public B b; 

    public A(B newB) { b = newB; } 

    private static A _empty = new A(B.Empty); 
    public static A Empty { get { return _empty; }} 

} 

public class B { 

    public C c; 

    public B(C newC) { c = newC; } 

    private static B _empty = new B(C.Empty); 
    public static B Empty { get { return _empty; } } 

} 

public class C { 

    public E e; 

    public C(E newE) { e = newE; } 

    private static C _empty = new C(E.Empty); 
    public static C Empty { get { return _empty; } } 

} 

public class E { 

    public string name; 

    public E(string newName) { name = newName; } 

    private static E _empty = new E(null); 
    public static E Empty { get { return _empty; } } 

} 

Exemple:

A a1 = new A(new B(new C(new E("Hello world!")))); 
A a2 = new A(new B(new C(E.Empty))); 
A a3 = new A(B.Empty); 

E e1 = a1.b.c.e; // e1.name returns "Hello world!" 
E e2 = a2.b.c.e; // e2 == E.Empty 
E e3 = a3.b.c.e; // e3 == E.Empty 
+0

Merci pour votre réponse très détaillée! –

1

Vérifiez ce grand article: Chained null checks and the Maybe monad

Un grand nombre de programmeurs ont rencontré une situation où, tout en accédant à une propriété d'objets imbriquées (par exemple, Person.Address .PostCode), ils doivent faire plusieurs vérifications nuls. Cette exigence apparaît fréquemment dans l'analyse XML où les éléments et les attributs manquants peuvent renvoyer une valeur nulle lorsque vous tentez d'y accéder (et qu'essayer par la suite d'accéder à Value lance une exception NullReferenceException). Dans cet article, je vais montrer comment une capture de la monade Maybe en C#, associée à l'utilisation de méthodes d'extension, peut être utilisée pour améliorer la lisibilité.

1

Voici la méthode d'extension de navigation sécurisée d'un homme pauvre qui enveloppe simplement une expression dans une tentative de recherche d'une valeur nulle.

https://gist.github.com/1030887

public static class Extensions 
{ 
    public static TResult SafeInvoke<TModel, TResult>(this TModel model, Func<TModel, TResult> expression, TResult nullValue = default(TResult)) 
    { 
     try 
     { 
      return expression(model); 
     } 
     catch (NullReferenceException) 
     { 
      return nullValue; 
     } 
    } 
} 

Vous pouvez appeler le code assez facilement.

public class MyModel 
{ 
    public Name Name { get; set; } 
} 

public class Name 
{ 
    public string First { get; set; } 
    public string Last { get; set; } 
} 

var model = new MyModel(); 
var firstName = model.SafeInvoke(x => x.Name.First, "john"); 
var lastName = model.SafeInvoke(x => x.Name.Last, "doe"); 

Console.WriteLine("{0}, {1}", lastName, firstName) 
// prints: "doe, john"