“移动”;如果;局部变量的语句条件使C#编译器不满意

“移动”;如果;局部变量的语句条件使C#编译器不满意,c#,compiler-construction,C#,Compiler Construction,你能给我解释一下以下情况的原因吗 今天我编写了代码(只更改了变量名称): 一切都很好,直到我决定将if条件移动到一个变量: private void Foo() { int firstInteger, secondInteger; const string firstStringValue = "1", secondStringValue = "2"; bool firstIntegerAndSecondIntegerAreSpecified = !s

你能给我解释一下以下情况的原因吗

今天我编写了代码(只更改了变量名称):

一切都很好,直到我决定将if条件移动到一个变量:

private void Foo()
{
    int firstInteger, secondInteger;
    const string firstStringValue = "1", secondStringValue = "2";

    bool firstIntegerAndSecondIntegerAreSpecified = 
        !string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger);

    if (firstIntegerAndSecondIntegerAreSpecified)
    {
        // Use firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}
现在,编译器在firstInteger和secondInteger变量下面加下划线,错误为“本地变量在访问之前可能未初始化”

但是为什么呢?我做的唯一一件事就是对代码进行了一点重构。在我看来,逻辑是一样的。

编译器(或者更确切地说,规范)没有发现指定的
firstIntegerAndSecondIntegerAreSpecified
的值与调用
int.TryParse
之间的关系。在第一种形式中,它可以计算出只有当对
int.TryParse
的两个调用都已执行,并且因此都有明确的赋值(由于
out
参数),执行才会进入主体。因此,
if
块中没有问题


明确赋值的规则没有涵盖这样的思想,即只有在两个调用都已执行时,
firstIntegerAndSecondIntegerAreSpecified
才会为真,因此在
if
块的主体中,变量仍然没有明确赋值,因此出现了错误。

编译器的设计不够聪明,无法确定布尔变量中的真值可以确保整数中的值被设置。编译器只跟踪执行路径,不跟踪可变值


在第一种情况下,编译器知道如果没有
TryParse
调用设置变量,就不可能输入if语句。在第二种情况下,if语句与
TryParse
调用分离,因此编译器必须跟踪变量值以找出关系。

在第一种情况下,编译器可以查看
if
条件,知道除非两个变量都有值,否则主体无法执行(
TryParse
始终设置其
out
参数,即使失败)


当您将该条件重构为一个变量时,编译器必须跟踪该局部变量,以确保它不能从被分配到用作条件时写入。由于编译器没有那么聪明,它无法确保您的变量已初始化(“明确分配”),因此它会给您一个错误。

只有在两个表达式都执行的情况下才能输入
if
语句,但是
bool
可能会因为短路而过早赋值-如果第一个字符串无法解析,编译器将跳过对第二个字符串的解析,因为无论结果如何,bool的值都必须是false。

编译器有时会出现此错误。当然,如果您遵循代码的逻辑,您将看到变量总是在使用前初始化。但是编译器不运行逻辑,它只根据一些基本规则进行操作。这就是为什么它经常出现此错误,即使实际上逻辑中没有错误


解决方案很简单:声明变量时只需初始化所有变量。

添加到Jon的答案中-

单独处理两个整数可能更容易,而且也不需要检查
NullOrWhiteSpace

int.TryParse(firstStringValue, out firstInteger)
    firstInteger++;

int.TryParse(secondStringValue, out secondInteger)
    secondInteger++;

您甚至可以用一个单独的方法提取这段代码

为什么要检查NullOrWhitespace?int.TryParse会为您处理它(即,空格会导致错误的返回值),从而使您的代码更具可读性。感谢您的提示,spender。您是对的,最好使用int.TryParse()仅此而已。是的,现在我明白了。谢谢你的帮助!我想,会有一些“逻辑”需求,因为提问者将两个整数加起来,当两个IFs在解析整数值后都返回true。如果是这样,你的建议将打破逻辑。否则,它肯定没问题。无论如何,不需要Nu你说得对!
int.TryParse(firstStringValue, out firstInteger)
    firstInteger++;

int.TryParse(secondStringValue, out secondInteger)
    secondInteger++;