在C#中,是否应该检查传递给方法的引用是否为null?

在C#中,是否应该检查传递给方法的引用是否为null?,c#,arguments,nullreferenceexception,argumentnullexception,C#,Arguments,Nullreferenceexception,Argumentnullexception,好吧,几个月前我问过,但最近由于整个“Windows Phone”的事情,我更加关注C# 那么,在C#中,是否应该费心在方法边界检查NULL?我认为这与C和C++不同,因为在C语言中通常可以确定给定的引用是否有效——编译器将阻止任何一个在任何地方传递未初始化的引用,因此唯一剩下的错误是它是空的。此外,在.NET框架中为这些东西定义了一个特定的异常,它似乎编码了当传递无效null时程序员认为应该得到的内容 我个人的观点是,打电话的人再次被打断了,并且说打电话的人应该在几天结束前都向他们扔NREs。

好吧,几个月前我问过,但最近由于整个“Windows Phone”的事情,我更加关注C#

那么,在C#中,是否应该费心在方法边界检查NULL?我认为这与C和C++不同,因为在C语言中通常可以确定给定的引用是否有效——编译器将阻止任何一个在任何地方传递未初始化的引用,因此唯一剩下的错误是它是空的。此外,在.NET框架中为这些东西定义了一个特定的异常,它似乎编码了当传递无效null时程序员认为应该得到的内容

我个人的观点是,打电话的人再次被打断了,并且说打电话的人应该在几天结束前都向他们扔NREs。然而,我对这个问题的把握要比我在本地代码领域中要少的多,C语言和C语言或C++语言相比,在编程方面有着不同的编程风格。
所以。。。你应该检查C方法中的空参数吗?

是的,检查它们。最好使用代码契约告诉调用方您需要非空参数

void Foo(Bar bar) {
    Contract.Requires(bar != null);
}
这是特别有利的,因为客户端可以准确地看到所需的参数

如果您不能使用代码契约,请使用guard子句

void Foo(Bar bar) {
    Guard.Against<ArgumentNullException>(bar == null);
}
void Foo(条形){
防范(bar==null);
}

快速失败。

我认为,如果您的方法不希望某个特定参数为null,则最好抛出
ArgumentNullException
(或使用协定作为)。在调用您的方法时,契约向客户机提供了一个更好的指标,即首先不要传递null


空检查是客户端的责任,这使得双方的代码都更易于维护(通常是双赢的情况)。。。至少我是这么想的。

至少在公共方法中验证所有参数是一种好的做法。这有助于更快地定位bug,并且在读取代码时也有帮助,因为它描述了方法的契约

我们实现了一个静态类AssertUtilities,它有一系列参数和状态验证方法。我相信有些人把这样的职业称为警卫

例如:

    public static void ArgumentNotNull(object argument, string argumentName)
    {
        if (argument == null)
            throw new ArgumentNullException(argumentName);
    }

    public static void ArgumentInRange(decimal argument, decimal minValue, decimal maxValue, string argumentName)
    {
        if (argument < minValue || argument > maxValue)
        {
            throw new ArgumentOutOfRangeException(
                argumentName,
                FormatUtilities.Format("Argument out of range: {0}. Must be between {1} and {2}.", argument, minValue, maxValue));
        }
    }

    public static void ArgumentState(bool expression, string argumentName, string formatText, params object[] args)
    {
        if (!expression)
            throw new ArgumentException(FormatUtilities.Format(formatText, args), argumentName);
    }

    public static void ArgumentHasText(string argument, string argumentName)
    {
        ArgumentNotNull(argument, argumentName);
        ArgumentState(argument.Length > 0, argumentName, "Argument cannot be an empty string.");
    }
公共静态void ArgumentNotNull(对象参数、字符串argumentName)
{
if(参数==null)
抛出新ArgumentNullException(argumentName);
}
公共静态void ArgumentInRange(十进制参数、十进制最小值、十进制最大值、字符串argumentName)
{
if(参数<最小值| |参数>最大值)
{
抛出新ArgumentOutOfRangeException(
我的名字,
FormatUtilities.Format(“参数超出范围:{0}。必须介于{1}和{2}之间。”,参数,minValue,maxValue));
}
}
公共静态void ArgumentState(布尔表达式、字符串argumentName、字符串formatText、参数对象[]args)
{
if(!表达式)
抛出新ArgumentException(FormatUtilities.Format(formatText,args),argumentName);
}
公共静态void ArgumentHasText(字符串参数,字符串argumentName)
{
ArgumentNotNull(参数,argumentName);
ArgumentState(argument.Length>0,argumentName,“参数不能是空字符串”);
}
所以。。。你应该检查C#方法中的空参数吗

是,当然,除非允许
null

更好的透视图:您应该始终检查有效的参数值。有时引用允许为null,有时
int
必须
=0
,或者字符串不能为null或空格

因此,以参数验证块开始每个方法是一个很好的实践

从那以后,有几个选择。对内部/私有方法的验证通常被认为不那么重要,并且出于性能原因,可以将其设置为有条件的(甚至可以忽略)

边界验证通常在发布版本中保留。几乎没有理由关掉它


大多数项目将使用一些助手类进行验证,以最小化方法内部的重复编码。内置的System.Diagnostics.Contracts类是一个非常好但还不是很流行的工具包。代码契约工具有许多关于参数验证的设置

在这里,
arguments
标记似乎有两种含义,是吗P@BoltClock:哈哈,我希望不是。我不想在这些事情上发动火战,但它们似乎无论如何都会发生。@downvoter:你对这个问题有什么特别的问题吗?will
Contract.Requires(bar!=null)标志
Foo(空),我怀疑它会这样,在这种情况下,与使用
if
的简单空检查相比,使用这样的东西有什么好处?Contract/Guard从何而来?我对那些片段不熟悉。:/这是否适用于公开的方法,还是组件内方法?@Bill ONeal:Code Contract位于.NET 4.0的System.Diagnostics.Contracts命名空间中
Guard
是一个常见的实用程序类,人们有自己的版本,但基本上,如果条件满足,它只会抛出type参数中指定的异常。@Bala R:您可以进行静态检查,它会成为文档的一部分。Contracts/Guard部分会稍微分散对答案的注意力。检查方式取决于几个因素。我喜欢合同,但它不会在任何地方都被接受(现在)。你认为这是公开库方法必须的,还是在内部也必须的?@Billy:只对公开库方法这样做。只有标记为
public
的方法才能执行任何类型的参数验证。对于内部和私有方法来说,这是不必要的花费,这也是使用冰毒的原因之一