为什么C#本地变量必须初始化?

7

我正在阅读MCTS自学培训包(70-536)第二版,在第一章中,我们有以下内容:

如何声明值类型变量 要使用一个类型,你必须首先声明一个符号作为该类型的实例。 值类型具有隐式构造函数,因此声明它们会自动实例化该类型; 与类不同,你不需要包含New关键字。构造函数将默认值(通常为null或0)分配给新实例, 但是在声明中始终应明确初始化变量,如下代码块所示:

'VB

Dim b As Boolean = False    

// C#  
bool b = false;

然而,当我编译以下控制台应用程序时,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ch1_70_536
{
    class Program
    {
        static void Main(string[] args)
        {
            bool b;
            Console.WriteLine("The value of b is " + b);
            Console.ReadKey();
        }
    }
}

我遇到了编译时错误

"使用未分配的本地变量b"

这甚至没有在勘误中提到。我是做错什么了还是这本书完全错了?

8个回答

14
本地变量必须被赋值后才能使用,而类字段则会获得它们的默认值。

以下是一个例子:

public bool MyMethod()
{
    bool a;

    Console.Write(a); // This is NOT OK.

    bool b = false;

    Console.Write(b); // This is OK.
}

class MyClass
{
    private bool _a;

    public void MyMethod()
    {
        Console.Write(_a); // This is OK.
    }
}

谢谢澄清。所以,正如Nick指出的那样,局部变量被初始化,但在我们显式地分配一个新值之前不能被使用。正确吗? - Kanini
不,它们不会自动初始化。这就是为什么你需要自己初始化它们的原因。只有类字段会自动为您初始化。@Nick谈到了类字段。 - Pieter van Ginkel

13

在VB方面,这本书大多数情况下都是正确的,但它未能提到在这种情况下VB和C#之间的区别。

在VB中,所有本地变量都会自动初始化:

Sub Test()
  Dim x As Integer
  MessageBox.Show(x.ToString()) 'shows "0"
End Sub

在C#中,局部变量不会被初始化,直到编译器才允许您使用它们:

void Test() {
  int x;
  MessageBox.Show(x.ToString()); // gives a compiler error
}

此外,不清楚书中引用的是局部变量还是类成员变量。在VB和C#中,类成员变量总是在创建类实例时初始化。

关于"值类型具有隐式构造函数"的说法是错误的,这简单来说并不正确。值类型会被初始化为它的默认值(如果被初始化了),并且没有调用构造函数。


4

您需要先为b分配一些内容,否则它不会被初始化。

尝试:

bool b = false; 
Console.WriteLine("The value of b is " + b); 
b现在为false。

2

您需要给b赋值

bool b = false;

在分配值之前,它是“未分配的”


2

方法中的变量(方法范围)需要显式初始化。类级别的变量(或“字段”)将自动使用默认值进行初始化。

class Test
{
   bool b; // =false
   int i; // =0
}

2

在C#和VB.net中,确保在调用任何变量之前都要先初始化它,这是一个重要的经验法则。 例如:

int myInt; // Simple Declaration and have no value in it 
myInt= 32; // Now you can use it as there is some value in it..

1

这个语句应该进一步说明,尽管局部变量可以在声明时不赋值,但在未被赋初始值之前是无法使用的:

构造函数会给新实例分配一个默认值(通常是 null 或 0),但您应该始终在声明中明确初始化变量...


我认为你的意思是“声明”而不是“初始化”。你不能在没有给变量赋值的情况下对其进行初始化,这就是你初始化时所做的事情。 - Guffa

1
在C#中,局部变量存储在堆栈中,编译器不会初始化它们以进行代码优化。
因此,引用(实际上对于值类型也是指针)指向未定义的内存空间。
因此,如果我们在使用局部变量之前没有将其设置为某些内容,则编译器知道我们将获得随机数据。
这里是一个示例IL代码:
static void Test()
{
  int a;
  int b = 2;
}

.method private hidebysig static 
  void Test () cil managed 
{
  // Method begins at RVA 0x3044
  // Code size 4 (0x4)
  .maxstack 1
  .locals init (
    [0] int32 a,
    [1] int32 b
  )

  // (no C# code)
  IL_0000: nop
  // int num = 2;
  IL_0001: ldc.i4.2
  IL_0002: stloc.1
  // }
  IL_0003: ret
} // end of method Program::Test

Int32 在堆栈中的位置 0 处被定义为变量 a,但未分配默认值。

因此它的值是不确定的,并且可以从内存单元中的任何值中获取。

对于在位置 1 的变量 b,稍后会被赋值,一切都正常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接