它是可以接受的使用异常,而不是冗长的空支票? [英] Is it acceptable to use exceptions instead of verbose null-checks?

查看:114
本文介绍了它是可以接受的使用异常,而不是冗长的空支票?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我recenly遇到一个项目,这个问题:有嵌套对象链,例如:A类包含B类的实例变量,这反过来具有C类的实例变量,......,直到我们有一个节点类Z树。

I recenly encountered this problem in a project: There's a chain of nested objects, e.g.: class A contains an instance variable of class B, which in turns has an instance variable of class C, ..., until we have a node in the tree of class Z.

     -----      -----      -----      -----               ----- 
     | A | ---> | B | ---> | C | ---> | D | ---> ... ---> | Z |
     -----      -----      -----      -----               -----  

每个类提供的getter和setter成员。父一个实例由XML解析器创建的,它是合法的链中的任何对象为null。

Each class provides getters and setters for its members. The parent A instance is created by an XML parser, and it is legal for any object in the chain to be null.

现在想象一下,在应用程序中的某一点,我们到A实例的引用,且仅当它包含为Z对象,我们必须在它调用一个方法。利用定期检查,我们得到这个代码:

Now imagine that at a certain point in the application, we have a reference to an A instance, and only if it contains a Z object, we must invoke a method on it. Using regular checks, we get this code:

    A parentObject;

    if(parentObject.getB() != null &&
        parentObject.getB().getC() != null &&
        parentObject.getB().getC().getD() != null &&
        parentObject.getB().getC().getD().getE() != null &&
        ...
        parentObject.getB().getC().getD().getE().get...getZ() != null){
            parentObject.getB().getC().getD().getE().get...getZ().doSomething();
    }



我知道异常不应被用于普通控制流,但不是上面的代码中,我看到了一些程序员这样做:

I know that exceptions should not be used for ordinary control flow, but instead of the previous code, I have seen some programmers doing this:

    try {
        parentObject.getB().getC().getD().getE().get...getZ().doSomething();
    } catch (NullPointerException e){}



这段代码的问题是,它可能迷惑维持时,因为它不清楚地显示对象可以为空。但在另一方面更加简练,少伸缩。

The problem with this code is that it may be confuse when maintaining it, since it doesn't show clearly which objects are allowed to be null. But on the other hand is much more concise and less "telescopic".

它是一个可以接受的这样做是为了节省开发时间?
怎能API进行重新设计,以避免这个问题?

Is it an acceptable to do this to save development time? How could the API be redesigned to avoid this problem?

我能想到的,以避免长期空检查的唯一的事情就是提供的无效实例嵌套对象,并为他们每个人提供的isValid 方法,但不会这创造了很多innecesary对象的内存?

The only thing I can think of to avoid the long null checking is to provide void instances of the nested objects and providing isValid methods for each one of them, but wouldn't this create a lot of innecesary objects in memory?

(我用Java代码,但同样的问题,可以适用于C#属性)

(I've used Java code, but the same question can apply to C# properties)

感谢。

推荐答案

我个人喜欢通过使用完全避免这个问题选项​​类型。通过调整这些方法/属性返回的值是选项< T> ,而不是 T 主叫方可以选择如何他们希望处理没有价值的情况下

Personally I like to avoid this problem altogether by using an option type. By adjusting the value returned from these methods/properties to be Option<T> rather than T the caller can choose how they wish to handle the case of no value.

一个选项类型可以有一个包含值与否(但选择本身不能为空),但主叫方不能简单地将它传递没有展开值,以便迫使调用者处理的事实可能没有价值。

An option type can either have a contained value or not (but the option itself can never be null), but the caller cannot simply pass it on without unwrapping the value so it forces the caller to deal with the fact there may be no value.

例如:在C#中:

class A {
    Option<B> B { get { return this.optB; } }
}

class B {
    Option<C> C { get { return this.optC; } }
}

// and so on

如果调用方想要扔,他们只是检索值没有显式检查,看看是否有一个:

If the caller wants to throw, they merely retrieve the value without explicitly checking to see if there is one:

A a = GetOne();
D d = a.Value.B.Value.C.Value.D.Value; // Value() will throw if there is no value

如果主叫方希望只是默认,如果任何步不具有的价值,他们可以执行映射/装订/投影:

If the caller wants to just default if any step doesn't have a value, they can perform mapping/binding/projection:

A a = GetOne();
D d = a.Convert(a => a.B) // gives the value or empty Option<B>
       .Convert(b => b.C) // gives value or empty Option<C>
       .Convert(c => c.D) // gives value or empty Option<D>
       .ValueOrDefault(new D("No value")); // get a default if anything was empty 

如果调用方希望在每个阶段违约,他们可以

If the caller wants to default at each stage, they can:

A a = GetOne();
D d = a.ValueOrDefault(defaultA)
     .B.ValueOrDefault(defaultB)
     .C.ValueOrDefault(defaultC)
     .D.ValueOrDefault(defaultD);



选项不是目前的一部分,C#,但我想有一天会成为。您可以通过引用F#库得到实现,或者您可能能够找到网络上的实现。如果你想我的,让我知道,我将它发送给你。

Option is not currently part of C# but I imagine one day will be. You can get an implementation by referencing the F# libraries or you may be able to find an implementation on the web. If you'd like mine, let me know and I'll send it to you.

这篇关于它是可以接受的使用异常,而不是冗长的空支票?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆