优雅的方式做链式空检查

时间:2014-04-10 11:47:44

标签: c# lambda

我正在使用此解决方案在我的代码中进行链式空检查

Cleaner way to do a null check in C#?

我只是想知道我们不能这样做。

bool returnValue = Helper.IsNull(nullPerson.contact.address.city);

那会更清洁吗?

我尝试编写这样的通用函数

public static bool IsNull<T>(this T rootObj)
{
  var visitor = new IsNullExpressionVisitor();
  //...
  //...
}

但后来我不知道如何从这个rootObject中创建表达式。

4 个答案:

答案 0 :(得分:4)

解决这个问题的一种方法(尽管仍然有点笨拙)是使用a construct that's sometimes called a "Maybe" monad

使用它,代码会变成这样的东西(你可能喜欢也可能不喜欢!):

string city = nullPerson.With(x => x.address)
                        .With(x => x.city);

然而,因为C# is getting the "Safe Navigation" operator (?.) in the next version*.

而高兴

使用这个新的?.运算符,代码如下所示:

city = nullPerson?.address?.city;

(*据称...)

答案 1 :(得分:1)

在阅读many questions试图解决同样的问题之后,我会想出来并且说目前无法创建真正优雅的链接null检查,优雅意味着不向链的每个组件添加间接。

在lambda评估中包装链可能是当时最不可行的方式,它只适用于:

CheckNull<string>(() => nullPerson.contact.address.city);

T CheckNull<T>(Func<T> f) { try { return f(); } catch { return default(T); } }

我宁愿鼓励你尝试按照Law of Demeter说明你的对象不应该知道它正在使用的对象的内部工作方式,并要求他们以任何他们想要的方式返回值而不是走下课堂树。

答案 2 :(得分:0)

不,没有。我见过的所有现有解决方案都远比问题困难得多。很多聪明的解决方案让其他人很难理解代码在做什么。

情况是你想做这样的事情:

city = selectedPerson.Contact.Address.City;

您可以做的是将支票封装在一个属性

City SelectedCity
{
    get
    {
       if (selectedPerson == null || selectedPerson.Contact == null || selectedPerson.Contact.Address == null)
           return null;
       return selectedPerson.Contact.Address.City;
    }
}

毕竟,想要访问这个长链属性的本质就是你有一个选定城市的概念。代码并不优雅,但至少它隐藏在一个地方,阅读它的任何人都可以立即掌握一个&#34; SelectedCity&#34;是

答案 3 :(得分:0)

在这里查看我的答案

https://stackoverflow.com/a/34086283/4711853

你可以简单地编写一个小的扩展方法,它可以让你像这样编写链式lambda:

var val = instance.DefaultOrValue(x =&gt; x.SecondInstance).DefaultOrValue(x =&gt; x.ThirdInstance).DefaultOrValue(x =&gt; x.Value);

您可以将此方法命名为