C#:在这种情况下,我是否应该费心检查null?

Svi*_*ish 5 c#

可以说我有这种扩展方法:

public static bool HasFive<T>(this IEnumerable<T> subjects)
{
    if(subjects == null)
        throw new ArgumentNullException("subjects");

    return subjects.Count() == 5;
}
Run Code Online (Sandbox Code Playgroud)

你觉得这个空检查和异常抛出真的有必要吗?我的意思是,当我使用这种Count方法时,ArgumentNullException无论如何都会被抛出,对吧?

我可以想到我应该这样做的一个原因,但是我想听听别人对此的看法.是的,我问的理由是部分懒惰(想要尽可能少地写),但也因为我认为一堆空检查和异常抛出了一些混乱的方法,这些方法往往最终是他们真的需要.有人应该知道比将null发送到方法更好:p

无论如何,你们怎么想?


注意: Count()是一个扩展方法,抛出一个ArgumentNullException,而不是一个NullReferenceException.见Enumerable.Count<TSource> Method (IEnumerable<TSource>).如果你不相信我自己尝试=)


注2:在这里给出的答案之后,我被说服开始检查更多的空值.我仍然很懒,所以我开始EnforceLokad共享库中使用该类.可以推荐看一下.而不是我的例子,我可以这样做:

public static bool HasFive<T>(this IEnumerable<T> subjects)
{
    Enforce.Argument(() => subjects);
    return subjects.Count() == 5;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 19

是的,它会抛出一个ArgumentNullException.我可以想到额外检查的两个原因:

  • 如果你以后回去并在调用之前更改方法以执行某些操作subjects.Count()并忘记在此时进行检查,则可能会在抛出异常之前产生副作用,这不太好.
  • 目前,堆栈跟踪将显示subjects.Count()在顶部,并且可能带有source参数名称的消息.这可能会让HasFive谁可以看到subjects参数名称的调用者感到困惑.

编辑:只是为了救我不得不在其他地方再写一遍:

召唤subjects.Count()将抛出一个ArgumentNullException,而不是一个NullReferenceException.Count()这是另一种扩展方法,假设System.Linq.Enumerable正在使用实现,那就是记录(正确)抛出一个ArgumentNullException.如果你不相信我,试试吧.

编辑:让这更容易......

如果您做了很多这样的检查,您可能希望这样做更简单.我喜欢以下扩展方法:

internal static void ThrowIfNull<T>(this T argument, string name)
    where T : class
{
    if (argument == null)
    {
        throw new ArgumentNullException(name);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后问题中的示例方法可以变为:

public static bool HasFive<T>(this IEnumerable<T> subjects)
{
    subjects.ThrowIfNull("subjects");    
    return subjects.Count() == 5;
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是编写一个检查值并返回它的版本:

internal static T NullGuard<T>(this T argument, string name)
    where T : class
{
    if (argument == null)
    {
        throw new ArgumentNullException(name);
    }
    return argument;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以流利地调用它:

public static bool HasFive<T>(this IEnumerable<T> subjects)
{
    return subjects.NullGuard("subjects").Count() == 5;
}
Run Code Online (Sandbox Code Playgroud)

这对于在构造函数中复制参数等也很有用:

public Person(string name, int age)
{
    this.name = name.NullGuard("name");
    this.age = age;
}
Run Code Online (Sandbox Code Playgroud)

(对于不重要的地方,您可能需要没有参数名称的重载.)