使用未初始化的变量 - 编译器坏了

时间:2012-03-01 09:55:45

标签: c# .net parsing compiler-construction

显然标题有些tongue in cheek,但我检查过并仔细检查过,我无法在逻辑中看到错误。

编译器抱怨变量parsed可能未在return语句中初始化。我不同意。我们哪个人错了,为什么?

public DateTime? Test(string nextDate)
{
    DateTime parsed;

    if (nextDate != "TBC" && !DateTime.TryParse(nextDate, out parsed))
    {
        throw new Exception();
    }

    if (nextDate == "TBC")
        return null;

    return parsed;
}

4 个答案:

答案 0 :(得分:6)

不,编译器根本没有破坏。

编译器无意告诉

if (nextDate != "TBC")

if (nextDate == "TBC")

互相排斥。它不会尝试在这两个条件之间建立任何联系。因此,如果你达到DateTime.TryParse(nextDate, out parsed),它就无法确定你肯定会调用return parsed;

基本上,编译器遵循相对简单的规则来确定明确的赋值(和可达性)。简单的规则易于推理,易于实现,并且易于编码。

幸运的是,您可以使代码更简单同时进行编译:

public DateTime? Test(string nextDate)
{
    if (nextDate == "TBC")
    {
        return null;
    }

    DateTime parsed;    
    if (!DateTime.TryParse(nextDate, out parsed))
    {
        throw new Exception();
    }
    return parsed;
}

现在我们正在处理一个位置的“TBD”的“特殊情况” - 然后我们可以忽略其余代码的特殊情况并调用{ {1}}无条件地保留TryParse明确分配。

答案 1 :(得分:3)

如果nextData == "TBC",则不会调用TryParse,因为无论如何整个条件都不能为真。因此,parsed可能无法初始化。

答案 2 :(得分:3)

你们两个都是对的。

未初始化变量检查的逻辑会查看所有可能的控制流路径,而无需进行更深入的逻辑分析。编译器的这一部分并不关心nextDate == "TBC"nextDate != "TBC"都不是真的。所以编译器就是他的PoV。

您不希望在编译器中过深地分析程序逻辑。你想要简单易懂的规则。在复杂的情况下,编译器需要在编译时基本上使用所有可能的输入值运行整个程序,以确定是否初始化了变量。

你是对的,因为你知道条件会有效,所以如果它没有被初始化,就永远不会达到变量的使用。


我会像这样重写你的功能:

public DateTime? Test(string nextDate)
{
    DateTime parsed;

    if (nextDate == "TBC" )
       return null;

    if(!DateTime.TryParse(nextDate, out parsed))
      throw new Exception();

    return parsed;  
}

但是,既然您正在抛出异常,您可能希望使用Parse代替TryParse

答案 3 :(得分:1)

as out是if语句的一部分,您必须将值初始化。

因为如果satement从左到右,在你的情况下nextDate != "TBC"首先得到验证,然后检查下一个语句。

所以这就像

if( fist check)
{
 if(second check)
 {
 }
}