C# 我应该在私有/内部方法中使用null参数吗?

C# 我应该在私有/内部方法中使用null参数吗?,c#,exception-handling,language-agnostic,software-design,C#,Exception Handling,Language Agnostic,Software Design,我正在编写一个库,它有几个公共类和方法,以及库本身使用的几个私有或内部类和方法 在公共方法中,我有一个空检查和一个抛出,如下所示: public int DoSomething(int number) { if (number == null) { throw new ArgumentNullException(nameof(number)); } } 但这让我想到,我应该在多大程度上向方法添加参数null检查?我是否也开始将它们添加到私有方法中?我应该

我正在编写一个库,它有几个公共类和方法,以及库本身使用的几个私有或内部类和方法

在公共方法中,我有一个空检查和一个抛出,如下所示:

public int DoSomething(int number)
{
    if (number == null)
    {
        throw new ArgumentNullException(nameof(number));
    }
}

但这让我想到,我应该在多大程度上向方法添加参数null检查?我是否也开始将它们添加到私有方法中?我应该只为公共方法这样做吗?

尽管您标记了
语言不可知论者,但在我看来,它可能并不存在一个通用的响应

值得注意的是,在您的示例中,您暗示了该参数:因此,如果语言接受暗示,则在您采取任何行动之前,它将在进入函数时立即触发错误。
在这种情况下,唯一的解决方案是在调用函数之前检查参数。。。但既然你在写图书馆,那就没有意义了

另一方面,在没有暗示的情况下,检查函数内部仍然是现实的。
所以在反射的这一步,我已经建议放弃暗示

现在让我们回到你的精确问题:应该检查到什么水平? 对于给定的数据块,它只会发生在它可以“输入”的最高级别(同一数据可能会出现多次),因此从逻辑上讲,它只涉及公共方法

这就是理论。但是,也许您计划了一个庞大、复杂的库,因此要确保注册所有“入口点”是不容易的。
在这种情况下,我建议相反:考虑只应用你的控件到处,然后只是省略它,你清楚地看到它是重复的。
希望这能有所帮助。

在我看来,无论是私有方法还是公共方法,您都应该检查“无效”数据


从另一个角度看。。。为什么仅仅因为方法是私有的就可以处理无效的东西?没有道理,对吧?始终尝试使用防御性编程,你的生活会更快乐;-)

最终,在这一点上没有统一的共识。因此,我不会给出肯定或否定的答案,而是尝试列出做出此决定的考虑因素:

  • Null检查您的代码。如果您的过程是简洁的,那么它们开头的null-guard可能构成整个过程的重要部分,而不表示该过程的目的或行为

  • 空检查明确表示一个前提条件。如果一个方法在其中一个值为null时将失败,那么在顶部进行null检查是一个很好的方法,可以向普通读者演示这一点,而无需他们查找它的解引用位置。为了改善这一点,人们经常使用名为
    Guard.AgainstNull
    的助手方法,而不是每次都要写检查

  • 私有方法中的检查不稳定。通过在代码中引入一个无法完全遍历的分支,就不可能完全测试该方法。这与测试记录类的行为以及该类的代码提供该行为的观点相冲突

  • 允许null通过的严重性取决于情况。通常,如果一个null进入了方法中,那么它将在几行之后被取消引用,您将得到一个
    NullReferenceException
    。这实际上并不比抛出一个
    ArgumentNullException
    差多少。另一方面,如果该引用在被取消引用之前被传递了很多次,或者如果抛出一个NRE将使事情处于混乱状态,那么尽早抛出就更重要了

  • 有些库,比如.NET的代码契约,允许一定程度的静态分析,这可以为您的检查增加额外的好处

  • 如果您正在与其他人一起处理一个项目,那么可能存在涵盖此内容的现有团队或项目标准

    • 以下是我的观点:


      一般情况 一般来说,出于稳健性原因,最好在方法中处理任何无效输入之前进行检查,无论是私有、受保护、内部、受保护内部还是公共
方法。虽然这种方法会付出一些性能代价,但在大多数情况下,这是值得的,而不是花更多时间调试和稍后修补代码


但是严格地说。。。 然而,严格地说,并不总是需要这样做。一些方法,通常是
私有的
方法,可以不进行任何输入检查而保留,前提是您可以完全保证不会对具有无效输入的方法进行单一调用。这可能会给您带来一些性能上的好处,特别是如果经常调用该方法来执行一些基本的计算/操作。在这种情况下,检查输入的有效性可能会严重影响性能


公共方法 现在,
public
方法更加棘手。这是因为,更严格地说,尽管访问修饰符本身可以告诉谁可以使用这些方法,但它不能告诉谁将使用这些方法。此外,它也无法判断这些方法将如何使用(也就是说,这些方法是否将在给定范围内使用无效输入调用)


最终决定因素 虽然代码中方法的访问修饰符可以提示如何使用这些方法,但最终,将使用这些方法的是人类,并且取决于人类如何使用它们以及使用哪些输入。因此,在一些罕见的情况下,可能存在仅在某些
private
范围内调用的
public
方法,并且在该
private
范围内,在调用
public
方法之前,保证
public
方法的输入有效

在这种情况下,即使访问修饰符是
public
,也没有任何r
        Dictionary<string, string> dictionary = new Dictionary<string, string>();
        string res;
        dictionary.TryGetValue("key", out res);
        var other = dictionary["key"];
public void Add(Person item)
{
    if(_size == _items.Length)
    {
        EnsureCapacity(_size + 1);
    }

    _items[_size++] = item;
}
public void Add(Person item)
{
    if(item == null)
    {
        throw new ArgumentNullException("Cannot add null to PersonList");
    }

    if(_size == _items.Length)
    {
        EnsureCapacity(_size + 1);
    }

    _items[_size++] = item;
}