参数异常与参数为空异常之间的区别是什么?

24

我正在重构一些代码,并添加一个将替代一个即将被弃用的方法的新方法。新方法具有以下签名:

FooResult Foo(FooArgs args) { ... }

弃用的方法包含了越来越多的参数。这些参数现在已经成为FooArgs类的属性。弃用的方法有几个保护条件,其检查空值的结构如下:

if (parameter1 == null)
    throw new ArgumentNullException(“parameter1”);
if (parameter... == null)
    throw new ArgumentNullException(“parameter...”);
if (parameterN == null)
    throw new ArgumentNullException(“parameterN”);

现在参数被整合到FooArgs类中,那我应该为FooArgs参数的各个属性抛出ArgumentNullException异常吗?

if (args.Property1 == null)
    throw new ArgumentNullException(“args.Property1”);
if (args.Property... == null)
    throw new ArgumentNullException(“args.Property...”);
if (args.PropertyN == null)
    throw new ArgumentNullException(“args.PropertyN”);

或者为整个FooArgs参数抛出一个更一般的ArgumentException

if (args.Property1 == null)
    throw new ArgumentException(“Property1 cannot be null.”, “args”);
if (args.Property... == null)
    throw new ArgumentException(“Property... cannot be null.”, “args”);
if (args.PropertyN == null)
    throw new ArgumentException(“Property2 cannot be null.”, “args”);

谢谢!


2
Closers 真的读懂了这个问题吗? - H H
4
不确定为什么这个问题已被关闭。对我来说,这似乎是一个完全合理的问题。无论如何,我想补充一点:如果你控制着FooArgs类,并且如果属性永远不应该为空,那么你可以将检查委托给类本身。 - Matthew Strawbridge
1
我已经从标题和问题本身中删除了“最佳实践”这个词,希望消除关闭它的顾虑。 - John Laffoon
这难道不是 .Net 4.0 中代码合约的用途吗?http://msdn.microsoft.com/en-us/library/dd264808.aspx - dash
1
你是否考虑过这样一种解决方案:参数是有效且一致的对象,没有空值?例如,可以使用 ProcessStartInfo 类,您可以将 FileName 设置为 null,但它仍将返回空字符串而不是null。这是一种空对象模式。我问这个问题是因为这种方法对于更复杂的对象可能会很不方便。 - wiero
4个回答

30

您需要添加一个检查参数本身是否非空的步骤。ANE 不适用于单个组件,因此您需要使用更通用的 AE,例如:

if (args == null)
    throw new ArgumentNullException(“args”);
if (args.Property1 == null)
    throw new ArgumentException(“Property1 cannot be null.”, “args”);
if (args.Property... == null)
    throw new ArgumentException(“Property... cannot be null.”, “args”);
if (args.PropertyN == null)
    throw new ArgumentException(“Property2 cannot be null.”, “args”);

1
ArgumentException 更通用,只应在参数无效时使用。而 ArgumentNullException 则特定于作为 null 引用传入的参数,其中 null 引用无效。 - Samuel Slade
6
@Slade所说的完全正确:如果args为null,则抛出ANE;如果args不为null,但其中一个组件为null(这当然会使args无效),则抛出更一般的AE。 - Sergey Kalinichenko

10

尽管我完全同意 dasblinkenlight 的答案,但你也可以考虑将对 FooArgs 的验证移入 FooArgs 类本身。如果这个类专门用于传递参数,则很可能不允许它有空属性,在这种情况下,我会允许其构造函数进行验证。


虽然dasblinkenlight的回答包含了我想要的解释,但我一定会研究这种方法。谢谢! - John Laffoon

2
在这种情况下,最好在该方法内部检查 FooArgs 参数是否为 null 引用,如果传入了 null 引用,则抛出 ArgumentNullException。然后如果其他方法或代码部分使用 args 类中包含的参数,则应该检查并根据需要抛出异常。但是,如果您的接受 args 类的方法正是使用所有参数的方法,则最好在该方法中检查有效参数,就像您建议的那样。
另外,只有对于空引用的参数才使用 ArgumentNullException。如果它只是一个无效值(例如空字符串),则应该使用更通用的 ArgumentException

2
这有点取决于你所使用的工具以及你对工具的感受(例如resharper、fxcops等)。一些静态代码分析工具接受这种方法:
throw new ArgumentNullException(“args.Property...”,"args");

拒绝此操作

throw new ArgumentNullException(“args.Property...”,"args.Property");

如果您想使用工具,则参数属性的空值断言必须引发ArgumentException异常。

也可以根据需要随时进行调整。任何能够向维护开发人员传达正确信息以帮助其正确传递参数的信息都是正确的信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接