Search code examples
c#dynamicnullchaining

calling trygetmember on chained null references


Is it possible to have a DynamicObject implementation that can be called in chain keeping a null reference to end if anywhere in the path a null reference is encountered, without throwing any exceptions?

a.b.c.e

for example: if a is null then a.b.c.e is null, or if c is null c.e is null etc.?

Very much like the Maybe monad from Haskell.


Solution

  • You can do something like that, but not for the outermost object, i.e. if a is null, you can't access a.b.

    You can make an empty instance of the A class, that returns empty instances for all it's properties. Then a.b would return an empty instance of B, which for the c property would return an empty instance of C, which for the e property would return an empty instance of E.

    You would not get a null value, but you would get an empty instance, which you could check with:

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

    If any of the properties along the way returns an empty instance, the end result would be 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; } }
    
    }
    

    Example:

    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