将“if”语句条件移动到局部变量会使C#编译器不满意

时间:2011-03-18 21:50:40

标签: c# compiler-construction

请您解释下列情况的原因。

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

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

    if (!string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger))
    {
        // Using firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}

在我决定将 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 变量,错误“在访问之前可能没有初始化本地变量”。

但为什么呢?我做的唯一一件事是重构代码。而且我认为它的逻辑是一样的。

6 个答案:

答案 0 :(得分:9)

编译器(或更确切地说,规范)没有发现firstIntegerAndSecondIntegerAreSpecified的值与int.TryParse的调用之间的关系。在第一种形式中,如果两个对int.TryParse的调用都已执行,则执行只会进入正文,因此两者都明确赋值(由于out参数)。因此if块没有问题。

明确赋值的规则并未涵盖firstIntegerAndSecondIntegerAreSpecified只有在两次调用都成立时才会成立的概念,因此在if块的主体中​​,变量仍然不是明确分配,因此错误。

答案 1 :(得分:6)

编译器的构建不够巧妙,无法确定布尔变量中的真值可确保设置整数值。编译器只跟踪执行路径,而不是可变值。

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:1)

只有在执行了两个表达式时才能输入if语句,但由于短路可能会过早地分配bool - 如果第一个字符串无法解析,编译器会跳过解析第二个字符串,因为无论结果如何,bool的值必须为false。

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

添加Jon的回答 -

分别处理两个整数可能更容易。并且无需检查NullOrWhiteSpace

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

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

你甚至可以用另外的方法提取这件作品