【问题标题】:Elegant way to do Chained Null Checks进行链式空检查的优雅方式
【发布时间】:2014-04-10 11:47:43
【问题描述】:

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

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 中表达出来。

【问题讨论】:

  • 我认为没有任何方法可以使用该签名。但是你可能有更好的运气传递一个 lambda。像这样:IsNull(() => nullPerson.contact.address.city)。
  • 根据你使用的dotnet版本,可以使用静态类Contractmsdn.microsoft.com/en-us/library/…
  • 如果存在空值,您希望链中的返回值nullPerson.contact.address.city 是什么?
  • @TonyHopkinson 很明显 OP 想要处理他的一个链为空,但你为什么称之为“移动/隐藏真正的问题”? 真正的问题是什么?

标签: c# lambda


【解决方案1】:

解决此问题的一种方法(尽管仍然有些笨拙)是使用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;

(*据称...)

【讨论】:

  • 唉,我不相信这个功能真的会进入 C#6 ......也许是 C#7?
  • 难道没有用户声音可以推送给操作员吗?
  • 我猜当它开始被滥用时,人们会很快停止高兴......
  • @TonyHopkinson 是的,我知道它鼓励火车残骸。 :)
【解决方案2】:

在阅读 many questions 试图解决同样的问题后,我会说,目前没有办法创建真正优雅的链式空检查,优雅意味着不向链的每个组件添加间接性。

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

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

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

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

【讨论】:

【解决方案3】:

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

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

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;
    }
}

毕竟,出于想要访问这一长串物业的本质,您确实有一个选定城市的概念。代码并不优雅,但至少它隐藏在一个地方,任何阅读它的人都可以立即掌握“SelectedCity”是什么。

【讨论】:

    【解决方案4】:

    在这里查看我的答案

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

    您可以简单地编写小型扩展方法,这样您就可以编写这样的链式 lambda:

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

    你可以把这个方法命名得更短

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-11
      • 2017-02-25
      • 2021-11-10
      • 2013-08-13
      • 2013-09-11
      • 2011-05-31
      • 1970-01-01
      • 2015-07-14
      相关资源
      最近更新 更多