调用方法时处理null对象

时间:2014-08-31 23:50:34

标签: c# c#-5.0 null-conditional-operator

我一直在寻找在调用方法(或方法链)时处理空对象的最佳选择。

我们的常见做法是检查条件:

if ( customObject != null ) {
    customObject.callMe();
}

使用扩展方法可以进一步改进:

Program customObject = null;
if (customObject.NotNull()) {
    customObject.CallMe();
}

public static bool NotNull(this object o) {
    return o == null;
}

请注意:我通常会忽略!从我的编程实践。因此,明智地说对我来说扩展方法很好。

然而,在处理涉及Method链的时候,它变得非常复杂。

customObject.CallMe().CallMe2() ex... 

您认为如何在C#中处理它,以便仅在CallMe不为空时调用customObject,并且仅在CallMe2返回时调用CallMe非空对象。

当然我可以使用If条件或三元运算符。但是,我想知道vNext,C#5.0是否有一些东西要提供。

5 个答案:

答案 0 :(得分:12)

在即将发布的C#6(vNext)中有?.运算符(Null条件运算符),它可以轻松地为每个嵌套属性链接空引用检查。

这方面的一个例子是:

int? first = customers?.[0].Orders?.Count();

这是Visual Studio UserVoice站点中的请求功能

Add ?. Operator to C#

您可以在Roslyn的Codeplex网站上查看C#6.0的所有新语言功能的状态:

C# 6 Language Features Status

答案 1 :(得分:4)

您目前可以编写以下类型的扩展方法:

public static class Extensions
{
    public static R IfNotNull<T, R>(this T @this, Func<T, R> @select) where T : class
    {
        return @this.IfNotNull(@select, () => default(R));
    }

    public static R IfNotNull<T, R>(this T @this, Func<T, R> @select, Func<R> @default) where T : class
    {
        return @this != null ? @select(@this) : @default();
    }

    public static void IfNotNull<T>(this T @this, Action<T> @action) where T : class
    {
        if (@this != null)
        {
            @action(@this);
        }
    }
}

然后像这样打电话给他们:

customObject 
    .IfNotNull(y => y.CallMe())
    .IfNotNull(y => y.CallMe2());

答案 2 :(得分:2)

C#5没有提供简化代码的功能。你坚持使用:

  • 嵌套条件
  • 复杂的三元表达式
  • Englobing try / catch捕获NullReferenceException(如果你的链中的null不是真的异常,你真的不应该这样做,即它不应该发生,但你想要一个keepsafe)。

然而,作为零传播算子,未来可能会更加明亮?是C#6的一个提议特性,并且有already be implemented is Roslyn,所以如果它在C#6中没有有效的话,那将是一个很大的惊喜。有了这个操作符,你就可以编写了

customObject?.CallMe()?.CallMe2()?.[...] 

编译器将为您创建嵌套if(甚至确保每个方法只调用一次)。所以,多一点耐心...

答案 3 :(得分:0)

C#6确实有?运算符,否则您可以查看monad,尤其是Maybe monad,例如herehereelsewhere。是否值得在非功能性语言中使用monad并不是为它们设计的,这是一个不同的问题。

答案 4 :(得分:-6)

这是异常处理的重点。如果您想要回应异常情况,例如从函数返回意外的 null ,那么捕获 NullReferenceException ,并从中调用您的恢复代码那里。异常本身将停止进一步调用,因此如果您希望完成所有操作,请不要执行任何恢复代码。 我不建议这是一个合理的回答,通常至少应记录这样的事情。

try
{
    customObject.CallMe().CallMe2()
}
catch (NullReferenceException ex)
{
   /* save enough details to determine why you got an unexpected null */
}

不要使用异常处理来完成正常的编程任务,但不要过度避免,通过检查每一个可能的意外事件,无论多么罕见。确定代码中可能出现的故障(您可以做任何事情),并在每个合理大小的块的末尾包含一个健康的 catch 列表。