这是否过于复杂以评估Main(string[] args)函数?

8

我有以下内容,并想知道初始测试是否过于严格:

static void Main(string[] args) {
    if (args.Length == 0 || args == null) {           
        //do X
    }
    else { 
        //do Y 
    }
}

换句话说,我的问题是args.Length是否可能为零,或者args是否为空...或者这些条件中只需要一个就足够了吗?

6
你的逻辑是错误的。如果 argsnull,会发生什么?检查 args.Length 将抛出 NullReferenceException 异常。 - Greg B
过度设计?其实并不是。除非你绝对需要在执行程序时提供响应,否则不要这样做。Greg B是正确的,先检查是否为空,然后再检查长度。 - Martin Ongtangco
通常情况下,在检查任何其他事项之前,你应该首先检查是否为null,因为如果args确实为null,那么你的第一个条件会抛出一个NullReferenceException - Ioannis Karadimas
5个回答

15

好的,Main被定义为永远不会使用null参数调用。如果它以某种方式收到了null参数,则表示您的环境已经损坏,无论您做什么,所有赌注都已关闭,因此检查null实际上没有任何帮助。

另一方面,如果您确实检查null,那么代码的读者和维护者就必须理解为什么。最初的程序员为什么要放置这样一个无用的检查?他知道我们不知道的东西吗?我们不能仅仅删除它,因为他可能揭示了一些奇怪的角落案例漏洞!

换句话说,您正在给程序添加复杂性,并使未来的代码读者犯错误。不要这样做。未来的用户可能是您自己。让您未来的自己感到高兴,并编写有意义的代码。

然而,在某些情况下,这样的空检查确实有意义,那么它必须是最左边的条件。

在像这样的测试中:args.Length == 0 || args == null,首先评估args.Length,如果失败,则将argsnull进行比较。换句话说,如果args为空,则您的代码将抛出异常。应该是args == null || args.Length == 0


4
我从未提到过性能问题。但请告诉我,依靠编程语言及其类库“做它所说的”有何不妥之处?如果您无法依赖于此,那么您该如何编写任何类型的代码?如果您不能信任这一点,那么您编写的每一行代码,包括您的空值检查都会受到怀疑和不可靠的影响。如果您想谈论糟糕的实践,那么这种毫无意义的混淆就是其中之一。说“如果整个世界上的一切都是腐败和不可靠的,我们该怎么办?我知道,检查 arg == null 就能解决问题。” 不,它解决不了。 - jalf
3
如果你的世界已经破碎,那么你将无法修复它,最好别再试了。你可以把这称为“希望”编程,如果这让你感觉更好些,但这是我们唯一能做的事情。我们必须希望编译器生成我们要求的代码。我们必须希望List<T>类实际上存储T类型的列表,我们必须希望在启动时调用Main方法。我们必须希望访问null对象会引发NullReferenceException异常。防御性编程无法保护你免受损坏的语言实现的影响。 - jalf
3
如果我骑自行车,为什么需要戴摩托车头盔呢?_以防未来有一天_自行车长出引擎。只戴自行车帽应该足够了,就像Jalf所说的,如果将来有人戴着摩托车头盔骑自行车,他们会很疑惑!(也许这不是我想到的最好比喻) - whytheq
4
“这个问题可以轻松地问及任何其他语言。” 真的吗?所以防御性编程是为了防止“你的代码突然成为另一种语言”的情况?我可以想象到这样的场景:“哦,该死,我过去8个月写的C++代码竟然变成了Prolog!该死,如果我早些时候就防备main被传入无效参数就好了。” 这个问题涉及到一个特定语言中的 Main 方法。在这种语言中,Main 只会在应用程序启动时由运行时调用一次,除非程序员疯了。 - jalf
2
@adelphus:我知道什么是防御式编程。但是OP提出了一个非常具体的场景中检查null的问题。我完全同意你,在许多其他情况下,检查null是有意义的。但我们不是在谈论那些情况。我们正在谈论一个C#程序,其中Main方法检查其参数是否为null。SO是一个学习论坛,每个程序员都应该学会的重要课程之一是“它取决于情况”。盲目地检查所有内容是否为空与检查没有任何东西一样愚蠢。 - jalf
显示剩余13条评论

10

根据这里,您只需要检查:

if (args.Length == 0)
{
    // Do X
}

虽然检查null不会有任何害处,但实际上没有必要。


2
+1 应用奥卡姆剃刀原则并提供链接。当然,其他答案对于一般情况是正确的,但这个问题非常具体。 - Mr Lister
@InternediateHacker - 很好,我记得有一个 MSDN 条目,但找不到了! - whytheq

3

如果涉及到性能不高、不常用的函数,增加额外的控制永远不是坏主意。所以我会说,不,这并不过度。

还有一件事:首先检查null,然后检查Length


5
将没有实际意义的代码添加到程序中是一个非常不好的想法。这会使代码混乱,难以阅读和理解,并且简单地增加了维护代码的工作量。因为Main函数不会使用空参数调用,所以不要试图在代码中测试"如果它确实这样做会怎么样",从而增加代码的复杂性。 - jalf
1
@Tigran:服务包不会更改语言规范以破坏现有程序。而且如果他们这样做,那么需要更多的空检查才能修复您的程序。如果发布了这样的服务包,它将破坏更多内容。但是想象一下,你没有编写这段代码,而是阅读它。想象一下你必须维护它。当我阅读时,我的反应是“什么?为什么需要这个空检查?原作者知道我不知道的东西吗?” - jalf
2
也许我做不到。但如果不能,那么你就没有维护过很多代码。简单性很重要。理解代码为什么看起来像这样是非常重要的。如果你不能给出一个好的理由,解释为什么你的代码看起来像它想要的那样,我不想去维护它。 - jalf
1
@adelphus:「不应该发生」、「不会发生」或者「不能发生」是有区别的。在这种情况下,args 永远不会是 null(除非有人在应用程序内部明确调用并传递了 null)。这不是一个库函数;它是 CLR 规范的一部分。这不仅仅是因为它「不应该」发生;除非你从应用程序内部(错误地!)调用 Main,否则它不会发生...或者出现了无法信任运行时的严重问题。如果你甚至不能信任运行时正确启动你的应用程序,那么从那一点开始你如何能够信任任何东西呢? - cHao
1
我喜欢听到人们说“<x>永远不会发生……除非<y>”。我非常喜欢,以至于当<y>发生并且有人不得不清理残留物时,我经常拥抱开发者。 - adelphus
显示剩余29条评论

3
如果没有输入数据,则args.Length等于0,但不是null。 如果有任何输入数据,则args.Length等于输入参数的数量。 总之,args不能为null,但长度可以为零。
PS:始终首先检查是否为null。

0
if (args == null)
{
    Console.WriteLine("args is null"); // Check for null array
}
else
{
    if (args.Length == 0)
    {
        //do X
    }
    else 
    { 
        //do Y 
    }
}

你可以使用 if (args == null) { ... } else if (args.Length == 0) { ... } else { ... } 来简化代码,省去一层花括号。顺便说一下,在大多数情况下,处理 null 和空数组的分支可能是相同的。 - Joey
@Joey 关于括号,我认为这对其他人更易读。关于第二个评论,你错了,如果 args 为空,则检查 args.Length 将抛出 NullReferenceException! - Dor Cohen
4
这就是为什么你需要首先检查null,然后再检查Lengthif (args == null || args.Length == 0) ... - Joey

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