2014-08-31 98 views
4

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

这是我们共同的做法,以检查与if条件:

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

可以通过使用扩展方法进一步提高:

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

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

请注意:我通常会忽略!从我的编程练习。因此,对我来说,明智的做法是推广方法很好。

但是,在处理涉及方法链时,它变得非常复杂。

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

你如何看待它可以在C#进行处理,从而使CallMe被称为只有当customObject不是null CallMe2被称为只有CallMe返回非空对象。

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

+6

以何种方式使用NotNull()是一种改进? – 2014-08-31 23:52:20

+0

通过获取扩展方法来玩实际的情况,我可以控制我定义为Null因此有一个改进。 (我通常忽略!从我的编程实践中)。 – codebased 2014-09-01 00:00:43

+0

至少如果您想查看[空对象模式](http://stackoverflow.com/questions/1178399/how-do-i-create-a-null-object-in-c-sharp) – Jonesopolis 2014-09-01 00:01:13

回答

12

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

这方面的一个例子是:

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

这是在Visual Studio UserVoice的网站要求的功能

Add ?. Operator to C#

你可以看到所有的新的语言特性的地位Codeplex站点上的Roslyn C#6.0:

C# 6 Language Features Status

+0

相当引人注目的新功能 – Jonesopolis 2014-09-01 00:21:59

+0

好吧,现在有道理,目前没有办法,所以我接受这个作为我的答案,因为这正是我所期待的。 我听说过吗?但没有给予太多的关注。谢谢Scott – codebased 2014-09-01 00:39:21

-7

这是异常处理的要点。如果你想回应异常的情况,比如从一个函数返回一个意外null,然后catchNullReferenceException,并从那里调用你的恢复代码。异常本身会阻止进一步的调用,所以如果你想完成所有这些,就不要执行恢复代码。 我不建议这是一个合理的回应,通常至少应该记录这样的事情。

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

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

+8

-1:绝对不是。 'NullReferenceException'几乎总是代表你的代码中的一个bug。它不应该被“处理” - 它应该是_fixed_。 – 2014-09-01 00:11:37

+0

大多数例外情况代表应该修复的事情。但是在运行中立即修复它们是不实际的。因此存在异常,因此可以记录和解决问题。就像我说的那样,不要有意使用它们来控制流量,但如果这个机制没有用处,它就不存在了。一直检查空值不是一个更好的解决方案,因为空返回可能是一个错误。 – 2014-09-01 00:14:43

+1

你完全错了。该机制不存在让您忽略异常。它的存在是为了让您了解代码中的错误,并且可以尽快修复它。或者你认为程序不能崩溃吗? – 2014-09-01 00:16:03

2

C#5没有什么可以简化您的代码。你被卡住或者:

  • 嵌套如果条件
  • 复杂三元表达式
  • Englobing try/catch语句捕捉的NullReferenceException(你真的不应该这样做,如果你的链条空是不是真的exceptionnal,即它不应该发生,但你想保持安全)。

然而,未来可能会更加光明,因为空传播运算符?是C#6提议的特性,且具有already be implemented is Roslyn,所以这将是一个巨大的惊喜,如果它在C#6,有效地不通过此操作员,你将能够编写

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

,编译器会创建嵌套如果你(甚至确保每个方法只被调用一次)。所以,多一点耐心......

+0

这究竟如何比一个例外更好?它基本上是一种自动饮食异常的方式。您试图忽略返回的null并删除执行链,而不解决逻辑错误。 – 2014-09-01 00:26:40

+1

@JonJayObermark比吃一个例外更好,因为新的操作符永远不会引发异常。这不是一个尝试/捕捉。它评估表达式,检查结果是否为null,如果不是,则调用method/property/field,否则返回null。这里没有逻辑错误,除了首先在语言中允许空引用的错误之外。这可能是一个设计错误(我确实相信),但至少现在我们有一个更容易处理这个错误的新工具。 – Falanwe 2014-09-01 10:03:32

+0

好的,但是你希望不需要检查列表是否为空,或者是否有其他各种意想不到的事情发生。任何你没有选择**的设计,使有意义的**真的是一个例外,不管你是否对待它。 – 2014-09-01 14:45:33

0

C#6确实有?算子,否则你可以看看单子,特别是Maybe monad,例如, herehereelsewhere。是否值得使用非功能性语言中的单声道,这与设计时不考虑它们是一个不同的问题。

+0

IEnumerable,Nullable,Func,Lazy和其他一些内置类型让我相信这是值得的;)事实上,C#中最新且最吸引人的语言特性与monad或comonads有关(Task ...) – Falanwe 2014-09-01 10:07:50

+0

@Falanwe同意,但是让我的头像一个概念并不容易,因为我对函数式语言不太熟悉,而且我也懒得去解决一些'if(foo == null)'块在这种情况下。 – 2014-09-01 10:13:36

+0

monads的一个很好的事情是,你并不需要理解它们来使用它们。而当你了解它们时,它开启了如此广阔的可能性...... – Falanwe 2014-09-01 11:33:21

3

你可以写目前这些种类的扩展方法:

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

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

-2

如今人们已四分五裂,它假定你是不是白痴答案,这里假设你是一个人。

您应该在customObject创建时检查,,因为这是您应该知道为什么得到空值的点。如果你没有检查,那么现在最好的办法就是让你的代码抛出异常。如果仍然有一些东西可以做到,即使没有明确需要的对象,也可以解决这个问题,但可能不会有这样的情况,但可以在产品编号中解决这个问题。

所有忽略意外空值的意义的机制,都只是让我们早先注意到失败,包括习惯性地过度使用提议的空传播操作符,以及在使用前检查对象的所有习惯。他们正在寻求对灾难作出有效回应,以最大限度地减少对其的关注。

如果您用一个对象的无效信号传递重要信息,那可能是一个糟糕的设计选择,并且您应该在引入它时将null转换为更多可用的信息。

在使用对象之前测试对象的意外无效,而不是在产生对象之后才能真正帮助任何人。这是一个代码的气味,表示你已经放错了地方的责任,可能在这些方式中的一种:

  1. 你不愿意去挑战的人谁没有足够的解释
  2. 做出尴尬的设计决策,你不觉得你有控制在你已经注册的东西上,但却懒得无法包装它
  3. 你不认为空值应该存在,而你试图忽略它们,所以你没有想过通过任何的策略。

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

在很多工作场所,在任何地方放一个空的块是明确的未来工作文件。所以它正在做一些事情。但离开它永远不会有一个应该代表良好代码的选项。这样的块将更合理地将异常转换为响应,该响应创建将来的工作来修复错误的来源,即使代码块实现了以更本地方式解决问题的解决方法。

相关问题