谁的错误是NullReferenceException?

时间:2010-06-04 13:57:39

标签: c# .net nullreferenceexception

我目前正在开发一个通过属性公开内部List的类。列表应该并且可以修改。问题是,内部列表中的条目可以从类外部设置为null。

我的代码实际上是这样的:

class ClassWithList
{
    List<object> _list = new List<object>();

    // get accessor, which however returns the reference to the list,
    // therefore the list can be modified (this is intended)
    public List<object> Data
    {
        get
        {
            return _list;
        }
    }

    private void doSomeWorkWithTheList()
    {
        foreach(object obj in _list)
            // do some work with the objects in the list without checking for null.
    }
}

所以现在在doSomeWorkWithTheList()中,我总是可以检查当前列表条目是否为空,或者我可以假设使用此类的人没有将条目设置为null的好主意。

所以最后问题最终出现了:在这种情况下,谁的错误是NullReferenceException?是类开发人员没有检查null的所有错误(这通常会使代码 - 不仅在这个类中 - 更复杂)或者是这个类的用户的错误,因为将List条目设置为null doesn'真的有道理吗?除了在一些非常特殊的情况下,我倾向于通常不检查null的值。这是一种糟糕的风格或事实上的标准/标准吗?

我知道这可能没有最终的答案,我只是缺少足够的经验来处理这样的事情,因此想知道其他开发人员对这些案例的看法,并希望听到关于检查null(或不是)的现实情况。< / p>

12 个答案:

答案 0 :(得分:7)

如果您公开列表,则允许您的班级用户随意添加null个参考文件 如果您允许用户随意添加null引用,则您的类需要为列表中的null引用做好准备。

private void doSomeWorkWithTheList()
{
    foreach(object obj in _list)
        if (obj != null)
           // do some work with the object
}

如果您不喜欢这样,请不要公开列表(应该公开为IList<T> btw),但是返回一个不允许null引用的类似列表的集合加入。

答案 1 :(得分:7)

很抱歉直言不讳,但如果你的代码不合时宜,那就是你的错。如果你的代码的其余部分有这个要求,你如何封装列表,并公开一个null-checking add方法?也许您的班级可以实施IList,并在内部存储您要处理的列表 - 然后在Add方法中,您只需要抛出NullArgumentException或忽略null并继续......

答案 2 :(得分:2)

使用Collection&lt; T&gt;,它是List&lt; T&gt;的内置可自定义包装器。然后,您可以覆盖InsertItem和SetItem,如果该项为null,则抛出异常。

答案 3 :(得分:1)

如果您在列表中允许null,那么您需要检查它们。如果你想在这里分配“责备”,那么它就是这个类,而不是类的用户。通过一些getter和setter可以很容易地阻止null将它们放入列表中,如果它们不属于它的话。

答案 4 :(得分:1)

如果将List设置为NULL对于类的使用没有意义,那么错误在于类设计者,他负责阻止对该类的操作。

答案 5 :(得分:1)

这取决于你想对doSomeWorkWithTheList()中的列表做什么,以及如果值为null你会怎么做。

我要么检查null并且自己抛出一个Exception(带有“无效列表值,不允许null”之类的消息)或者不通过创建Collection<>的子类来允许空值,如果有人使用它会抛出AddItem,其值为空。

通过提供API,您还可以提供合同。如果合同中显示“不允许空值”,则API的用户有责任不将任何内容设置为空,并且您有责任确保遵循合同。

答案 6 :(得分:1)

如果您不想在列表中使用空值,那么您将在某处抛出异常。问题是:在哪里?当用户尝试添加到列表或您尝试处理它时?

我会在类的消费者试图添加到列表中时抛出一个ArgumentException,因为如果你无法使用它,那么允许他们添加项目的重点是什么。但是你会想要抛出异常。不要让消费者认为一切只是因为他们没有被告知其他事情。

答案 7 :(得分:1)

只是过滤列表以避免NRE是不好的做法,它隐藏了客户端代码中的错误。代码必然会在没有任何好方法诊断原因的情况下发生故障。让它炸弹。

将客户端代码的集合对象公开给派对也不是一个很好的做法。从IList<object>派生您的课程( 是否为对象?)。您将IList的方法委派给您班级中的私人List<object>字段。但是,您可以覆盖索引器并实现Add方法,以验证客户端代码未在集合中放置空值。如果真的有必要的话。

答案 8 :(得分:0)

您不应该相信用户不要做这样的事情。有时列表条目将设置为null。这些事情发生了。我会尽可能地抓住它。如果您公开列表,则始终存在空引用的可能性,因此您应该考虑到这一点。

这不是你的错,但是它实际上是否是用户的错也无关紧要 - 你会受到指责。

答案 9 :(得分:0)

这是试图使用List的人的错。你总是必须假设它可以为null,所以你应该检查它。

这涉及防御性编程以及如何保护代码免受其他人的影响。

第8章中的

Code Complete涉及这个概念。

答案 10 :(得分:0)

Add code contracts。然后,您可以在方法start,返回值以及使用不变检查时检查空值。然后,根据您拥有的Visual Studio版本,您可以在编译时和运行时检查。

答案 11 :(得分:0)

我真的不喜欢将空值插入到除数组之外的任何类型的集合中。

我觉得这里有很多海报。对我来说,任何将null粘贴到某个其他对象属性的集合中的人都应该得到他后来得到的东西。

当我编写自定义哈希表时(System.Generic.Dictionary有一些问题,我不会在这里讨论)我决定在找不到时返回null。由于我没有插入空值,这使我的生活变得更轻松。