为什么必须在if语句的范围之外声明变量才能存在?

时间:2013-07-26 19:42:42

标签: c#

为什么必须在if语句的范围之外声明变量才能存在?

例如,以下代码无法编译:

DateTime? myDate;
if (myDate != null)
{
    DateTime runDate = DateTime.Now;
}
else
{
    DateTime runDate = DateTime.Now.AddDays(1);
}

string foo = runDate.toString();

我理解问题是我需要在if语句之前声明runDate,但为什么呢?如果编译器确实允许这段代码工作,那么它真的与之前声明它有什么不同吗?或者更好的措辞,为什么从事语言/框架工作的开发人员决定这样做呢?

8 个答案:

答案 0 :(得分:14)

好吧,考虑一下,从你的例子中得出:

DateTime? myDate;
if (myDate != null)
{
    String runDate = DateTime.Now.ToString();
}
else
{
    DateTime runDate = DateTime.Now.AddDays(1);
}

string foo = runDate.ToString();

根据您的提案,runDate(分配foo时)的类型在编译时未知,可以是stringDateTime。静态类型语言不允许这样做。

答案 1 :(得分:2)

变量在声明范围之外不存在。

在您的情况下,变量runDate是在if语句中创建的,因此不能在外部使用。

这是允许的

DateTime? myDate;
DateTime runDate;
if (myDate != null)
{
     runDate = DateTime.Now;
}
else
{
    runDate = DateTime.Now.AddDays(1);
}

string foo = runDate.toString();

答案 2 :(得分:1)

答案 3 :(得分:0)

即使在DateTime runDate的两边声明了if,编译器也不知道除非进行深入分析以确保编译器不在那里。此外,在if范围内声明超出范围,因为您在if范围内声明,如果要在方法中使用某些内容,则需要在方法的范围,并在if

中使用它
DateTime? myDate ;
DateTime runDate ;

if (myDate != null)
{
    runDate = DateTime.Now;
}
else
{
    runDate = DateTime.Now.AddDays(1);
}

string foo = runDate.toString();

答案 4 :(得分:0)

因为C#中的变量仅在其块中有效。尝试在if语句中创建runDate变量没有任何问题。失败的是,试图在它的块之外使用runDate变量。

声明必须位于其使用的最外面的块上。你当然可以在if语句中移动runDate.ToString(),如果你愿意的话,它会编译。

答案 5 :(得分:0)

由于块范围。编译器运行起来要容易得多,而且更合乎逻辑。每个块(一组开括号和闭括号)都有它的局部变量,它们只在其中的范围内,以及任何子块。这是有道理的,可以阻止人们疯狂。

答案 6 :(得分:0)

想象一下,你有以下几点:

if (something)
{
    string foo = "Abc";
}
else if (somethingelse)
{
    DateTime foo = DateTime.Now;
}
else
{
    //Do nothing
}
Some.Method(foo); //What type is foo, string or DateTime? Does it even exist?

正如您所看到的,如果您允许在if / else块范围内声明的变量在这些块之外使用,则这些声明可能会相互冲突(甚至在某些“if”分支中丢失) “)。因此,该语言的设计者决定不允许这样做。 (另外,一般来说,块中声明的C#中的变量只能在该块中使用。仅为if语句更改此内容会很奇怪且不一致。)你仍然可以在块内声明变量,你就是不能使用这些外面的变量。

答案 7 :(得分:0)

思想实验:

if (condition)
{
    T x;
    …
}
else
{
    T x;
    …
}
x = …;

您的想法可能是x = …;始终有效,因为无论x语句采用什么路径,都保证声明if

这可能是对的,但这种情况实际上是一个非常特殊的情况。它只需要很少的东西,事情开始分崩离析:

  • 省略else条款
  • x xor if条款中遗漏else声明

在这两种情况下,x将不再保证在每种情况下都被声明,因此如果x知道condition为真,则编译器只会将condition的赋值识别为有效(或者,x具有一个值,使得该子句将被执行,分别包含condition的声明。要知道condition的实际可能值,编译器必须执行的不仅仅是代码的静态分析;在最糟糕的情况下,它可能必须实际运行您的代码,以及通过它的所有可能路径。但是编译器应该如何运行它只是要编译的代码......?

如果condition的值取决于随机数生成器或用户I / O,该怎么办?这意味着编译器无法确定性地找到if语句执行时可能具有的值condition。简而言之,为了节省时间,编译器认为不能找出x可能具有的值,并完全放弃非静态分析是合理的。

  • ifelse条款
  • 内省略x = …;声明

在这种情况下,你不会对编译器抱怨{ }的所有人感到懊恼,对吧?

结论:

如果允许变量的“条件”声明,对代码的少量更改可能会以不同的,可能意外的方式破坏您的代码。

为了让您和您自己的生活更轻松,编译器坚持您只从引用它们的x = …;块中引用局部变量。这有两个好处:

  • 编译器只需执行简单的静态分析即可;不需要运行代码来分析它以进行编译(即没有鸡和蛋的问题)。

  • 您的代码(x)只会在您删除else的声明时中断,而不会在您执行看似无关的操作时中断,例如删除{{1}}子句。< / p>