显然标题有些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 :(得分: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)
{
}
}