为什么我们不能在if语句中定义变量?

时间:2011-07-02 19:52:33

标签: c# language-design scope

也许此问题之前已得到解答,但if这个词经常发生,很难找到它。

这个例子没有意义(表达式总是正确的),但它说明了我的问题。

为什么此代码有效:

StringBuilder sb;
if ((sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

但是这段代码不是:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

我发现了关于while声明的类似问题。那里接受的答案是在while语句中,这意味着变量将在每个循环中定义。但是对于我的if语句示例,情况并非如此。

那么我们不允许这样做的原因是什么?

6 个答案:

答案 0 :(得分:37)

这是因为C#语言规范的第8.5.1节。规定:

  

此外,局部变量声明中的变量初始值设定项与声明后立即插入的赋值语句完全对应。

这基本上意味着,当你这样做时:

StringBuilder sb = new StringBuilder("test")

实际上,你做的完全相同:

StringBuilder sb; sb = new StringBuilder("test")

因此,对!= null的检查不再有返回值,因为赋值不是单个表达式,而是一个语句,它是 local-variable-declarator < / em>由标识符后跟表达式组成。

语言规范给出了这个例子,说明了这一点:

void F() {
   int x = 1, y, z = x * 2;
}

完全等同于:

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}

答案 1 :(得分:15)

尝试C#7's Pattern Matching

使用您的示例:

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}

答案 2 :(得分:9)

这与语句和表达式之间的区别有关。表达式有一个值,而一个语句没有。

使用您的示例,请注意以下分类:

StringBuilder sb; // statement

sb = new StringBuilder("test") // expression

StringBuilder sb = new StringBuilder("test"); // statement

请注意,只有中间部分是表达式。

现在我们转到您的条件声明。使用not-equals运算符的语法是

expression != expression

所以在!=的两边你需要一些实际上有价值的东西(这才有意义)。因此,您不能在运营商的任何一方发表声明。这就是为什么你的代码的一个版本可以工作,而另一个版本没有。

答案 3 :(得分:2)

而不是:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

还可以写:

for (StringBuilder sb = new StringBuilder("test"); sb != null; sb = null) {
    Console.WriteLine(sb);
}

如果你的变量不为null,那么for循环将执行一次。在循环结束时,您的临时变量设置为null。然后循环条件计算为false,并且在执行右括号后继续执行下一个语句。正如你最初的if语句一样。

答案 4 :(得分:0)

C#7.0 introduced能够在条件内部声明out变量。与泛型结合使用,可以将其用于请求的结果:

public static bool make<T> (out T result) where T : new() {
    result = new T();
    return true;
}
// ... and later:
if (otherCondition && make<StringBuilder>(out var sb)) {
    sb.Append("hello!");
    // ...
}

您还可以避免使用泛型,而选择辅助方法:

public static bool makeStringBuilder(out StringBuilder result, string init) {
    result = new StringBuilder(init);
    return true;
}
// ... and later:
if (otherCondition && makeStringBuilder(out var sb, "hi!")) {
    sb.Append("hello!");
    // ...
}

答案 5 :(得分:-2)

与Jeff的评论一样,此代码的输出为空:

StringBuilder sb = new StringBuilder("test");

并且if语句需要一个值。