繁体   English   中英

调用方法时处理null对象

[英]Handling null objects when calling methods

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

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

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不是null CallMe2被称为只有当CallMe返回非空对象。

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

在即将到来的C#6(vNext)中有?. 运算符(Null条件运算符),它允许您为每个嵌套属性链接空引用检查。

一个例子是:

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

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

加? C#的运算符

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

C#6语言功能状态

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

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());

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

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

但是,作为零传播算子,未来可能会更加明亮? 是C#6的一个提议特性,并且已经实现了Roslyn ,所以如果在C#6中没有有效的话,那将是一个很大的惊喜。通过这个运算符,你将能够编写

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

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

C#6确实有? 运算符,否则你可以查看monad,尤其是Maybe monad ,例如这里这里其他地方 是否值得使用非功能性语言中的monad是一个不同的问题。

由于人们正在撕裂假设你不是白痴的答案,这里假设你是一个人。

您应该在创建customObject进行检查, 因为这是您可以知道为何获得null的点 如果你没有检查,那么现在最好的办法是让你的代码抛出异常。 如果仍然有一些你可以做的事情,那么在没有你明确需要的对象的情况下完全有意义,你可以在异常的捕获中修复它,但可能没有。

所有忽略意外null的重要性的机制只是传递失败而早先引起注意,包括习惯性过度使用所提出的零传播算子,以及在使用前检查对象的所有习惯。 他们正在寻求对灾难的有效回应,以最大限度地减少对它的关注。

如果您使用对象的null来表示重要信息,那么这可能是一个糟糕的设计选择,并且您应该在引入时将null转换为更有用的信息。

在使用对象之前测试对象的意外无效,而不是在对象产生之后对其进行测试,这对任何人都无法真正帮助。 这是一种代码嗅觉,表明你有错误的责任,可能是以下列方式之一:

  1. 如果没有充分的解释,你不愿意挑战做出尴尬设计决策的人
  2. 你不觉得你已经控制了你已经合并的东西但是懒得把它包起来
  3. 你不相信空值应该存在,并且你试图忽略它们,所以你没有考虑过它们的任何政策。

你指出的政策,即在不分析的情况下吃零和继续执行,这是一个糟糕的政策。 如果你打算保留它,这是我的另一个答案。 你应该做一些合理的事情。

在许多工作场所,将空挡块放在任何地方都是对未来工作的清晰记录。 所以它正在做点什么。 但是留下它永远不会有一个应该保持良好代码的选项。 即使代码块实现了以更本地方式解决问题的解决方法,这样的块也会更合理地将异常转换为创建未来修复错误源的工作的响应。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM