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

本文关键字:编译器 已损坏 变量 初始化 | 更新日期: 2023-09-27 18:26:09

很明显,标题有点开玩笑,但我已经检查了一遍又一遍,我看不到逻辑中的错误。

编译器抱怨变量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;
}

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

不,编译器根本没有坏。

编译器不应该告诉

if (nextDate != "TBC")

if (nextDate == "TBC")

相互排斥。它没有试图在这两种情况之间建立任何联系。因此,如果你到达return parsed;,它不能说你肯定已经呼叫了DateTime.TryParse(nextDate, out 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"的"特殊情况",然后我们可以在代码的其余部分忽略该特殊情况,并无条件调用TryParse,使parsed明确指定。

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

你们两个都是对的。

未初始化变量检查的逻辑着眼于所有可能的控制流路径,而不进行更深入的逻辑分析。编译器的这一部分并不关心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

因为out是if语句的一部分,您必须初始化该值。

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

所以这就像

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