例外をスローすることなく、パス内のどこかで null 参照が検出された場合に、最後まで null 参照を保持してチェーンで呼び出すことができる DynamicObject 実装を持つことは可能ですか?
a.b.c.e
例: a が null の場合、abce は null です。または、c が null の場合、ce は null です。
Haskell の Maybe モナドによく似ています。
この素晴らしい記事をチェックしてください:連鎖ヌルチェックと多分モナド
非常に多くのプログラマーが、ネストされたオブジェクトプロパティ(person.Address.PostCodeなど)にアクセスしているときに、いくつかのnullチェックを実行する必要がある状況に遭遇しました。この要件は、XML解析で頻繁に発生し、欠落している要素や属性にアクセスしようとするとnullを返す可能性があります(その後、ValueにアクセスしようとするとNullReferenceExceptionがスローされます)。この記事では、C#でのMaybeモナドのテイクを、拡張メソッドの使用と組み合わせて、読みやすさを向上させるためにどのように使用できるかを示します。
そのようなことはできますが、最も外側のオブジェクトに対してはできません。つまり、a
がnullの場合、にアクセスできませんa.b
。
A
クラスの空のインスタンスを作成できます。これにより、すべてのプロパティに対して空のインスタンスが返されます。次にa.b
、の空のインスタンスを返します。これは、プロパティの場合はの空のインスタンスを返し、B
プロパティc
の場合はの空のインスタンスを返します。C
e
E
null値は取得されませんが、空のインスタンスが取得されます。これを確認するには、次のようにします。
E e = a.b.c.e;
if (e != E.Empty) { ... }
途中のプロパティのいずれかが空のインスタンスを返す場合、最終結果はになります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; } }
}
例:
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
これは、nullref を探す try キャッチで式をラップするだけの、貧弱な安全なナビゲーション拡張メソッドです。
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;
}
}
}
コードはかなり簡単に呼び出すことができます。
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"