2012-03-01 52 views
3

显然标题是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; 
} 
+0

幽默是主观的。如果你坚持手头的问题,你可能会得到更好的回应。 – adelphus 2012-03-01 10:14:09

+0

@adelphus感谢您的建议,但我认为标题很好地描述了这个问题。这不应该是一个笑话。如果以某种方式冒犯了你,欢迎编辑它。无论如何,我已经得到了我的答案。 – fearofawhackplanet 2012-03-01 10:28:01

+0

那么,这不应该是一个笑话?那么你实际上认为你的代码有问题意味着编译器坏了?就我个人而言,我并不在乎,但是对于许多人来说,假设编译器(或操作系统或API或......)存在自己的代码问题是一个贫穷的开发人员的标志。 – adelphus 2012-03-01 11:17:11

回答

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”的“特殊情况”然后我们可以忽略其余代码的特殊情况,并无条件地致电TryParse,并保留parsed的明确分配。

1

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

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

所以这就像

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

如果nextData == "TBC",你TryParse没有被调用,因为整个状态不是真的呢。因此parsed可能未被初始化。

+2

我怀疑OP的观点是,如果'nextData ==“TBC”'那么我们将不需要'parsed'的值(因为我们之前返回) - 但编译器不必考虑这个。 – 2012-03-01 10:02:12

+0

你说得对。我怕我错过了一点... – 2012-03-01 10:08:02

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