为什么我的编译器会报错“使用未赋值的局部变量”?

92

我的代码如下

int tmpCnt;  
if (name == "Dude")  
   tmpCnt++;  

为什么会出现错误"Use of unassigned local variable tmpCnt"
我知道我没有显式初始化它,但由于默认值表格,值类型总是用0进行初始化。参考还提醒我:

请记住,在C#中使用未初始化的变量是不允许的。

但如果这已经默认完成了,为什么我还需要显式地执行它呢?如果我不这样做,会不会提高性能?

我有一个本地结构体,从未初始化过,在编译时没有错误。今天我创建了一个不同的结构体,处理方式完全相同,却得到了“未初始化本地变量错误”。在使用之前,所有成员都被设置为一个值,但是我不能首先将其设置为null,因为它只是一个结构体。编译的结构体仅包含int、bool和string。而出现错误的那个结构体还包含DateTime。"MyStructType myStruct = new MyStructType();" 消除了错误。这不是我第一次因为漏掉了几个级别的东西而受到影响。 - MickeyfAgain_BeforeExitOfSO
可能是为什么C#本地变量必须初始化?的重复问题。 - user12031933
10个回答

164

局部变量没有被初始化。你需要手动初始化它们。

成员变量则会被初始化,例如:

public class X
{
    private int _tmpCnt; // This WILL initialize to zero
    ...
}

但是局部变量不是这样:

public static void SomeMethod()
{
    int tmpCnt;  // This is not initialized and must be assigned before used.

    ...
}

那么你的代码必须是:

int tmpCnt = 0;  
if (name == "Dude")  
   tmpCnt++;  

简而言之,成员被初始化了,而局部变量没有被初始化。这就是为什么会出现编译器错误的原因。


2
@James: 你知道这是否仅是编译器为防止此类错误而设置的功能,还是C#编译器实际上延迟分配已声明局部变量的内存直到赋值?(例如,在C ++中,使用未分配的变量是“可以”的,即使这样变量的值不可预测。) - ybakos
3
编译器的特性可避免错误。对于本地变量的内存分配(当然,这只是引用类型的引用)在声明时进行。 - James Michael Hare
3
避免什么错误? - Raikol Amaro
使用新的 out var 变量 语法也会出现这个警告,我认为这种情况很烦人。 - mkb

19

默认赋值适用于类成员,但不适用于局部变量。正如 Eric Lippert 在 这个回答中所解释的那样,微软本来可以默认初始化局部变量的,但选择不这样做是因为使用未初始化的局部变量几乎肯定是一个错误。


9
以下变量类别被归类为“未分配”:
  • 最初未分配的结构变量的实例变量。
  • 输出参数,包括结构实例构造函数的this变量。
  • 本地变量,除了在catch子句或foreach语句中声明的变量。
以下变量类别被归类为“已分配”:
  • 静态变量。
  • 类实例的实例变量。
  • 最初分配的结构变量的实例变量。
  • 数组元素。
  • 值参数。
  • 引用参数。
  • 在catch子句或foreach语句中声明的变量。

3

本地变量没有默认值。

在使用之前必须明确赋值。这可以降低使用您认为已经赋予合理值的变量的机会,而实际上它具有一些默认值。


这难道不是为实例变量和类变量没有默认值辩护吗(它们确实有默认值)? - Peter Mortensen

1

默认值表仅适用于变量的初始化。

根据链接页面,以下两种初始化方法是等效的...

int x = 0;
int x = new int();

在你的代码中,你仅仅定义了变量,但是没有初始化对象。

1
一个非常愚蠢的错误,但是如果您没有实例化它,您也可以使用类来获取它。
BankAccount account;
account.addMoney(5);

以上代码会产生相同的错误,而以下代码不会产生错误:
class BankAccount
{
    int balance = 0;
    public void addMoney(int amount)
    {
        balance += amount;
    }
}

按照以下步骤消除错误:

BankAccount account = new BankAccount();
account.addMoney(5);

0

虽然值类型具有默认值并且不能为 null,但它们也需要明确初始化才能使用。您可以将这两个规则视为并排规则。

值类型不能为 null - 编译器保证了这一点。 如果你想知道为什么,那么你得到的错误消息就是答案。一旦调用它们的构造函数,它们就会被初始化为它们的默认值。

int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0

1
这不更取决于变量类型而不是它是值类型还是引用类型吗?值类型的实例变量不是自动初始化为默认值吗? - Peter Mortensen

0

请参考此线程,其中涉及未初始化的布尔值,但它应该能回答你的问题。

本地变量不会被初始化,除非你调用它们的构造函数(new)或为它们赋值。


0

本地变量不会自动初始化。这只会发生在实例级别的变量。

如果您想要初始化局部变量,您需要显式地进行初始化。在这种情况下(如链接文档所述),可以通过设置值为0或使用new运算符来实现。

您展示的代码确实尝试在将变量tmpCnt初始化为任何值之前使用它的值,编译器正确地发出了警告。


0
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize

在循环内部分配值(_getCurrentHolidayList)。
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
                            if (_holidayItem.CountryId == Countryid)
                                _getCurrentHolidayList = _holidayItem.Holiday;                                                   
}

当你像下面这样将本地变量传递给另一个方法时,它会抛出错误(使用未分配的变量),即使在声明时使用了可空类型。

var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);

如果你像下面这样提到,它不会抛出任何错误。

IEnumerable<DateTime?> _getCurrentHolidayList =null;

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