C# 变量初始化问题

Posted

技术标签:

【中文标题】C# 变量初始化问题【英文标题】:C# Variable Initialization Question 【发布时间】:2010-10-31 10:49:33 【问题描述】:

我是否初始化一个整数变量有什么区别:

int i = 0;
int i;

编译器或 CLR 是否将其视为同一件事? IIRC,我认为它们都被视为同一个东西,但我似乎找不到这篇文章。

【问题讨论】:

Fields 总是自动初始化为字段类型的默认值,在 int 的情况下为零。字段被认为是明确分配的;您甚至可以在明确分配之前阅读它们的内容。 Locals 不被认为是明确分配的;在读取本地内容之前,您需要执行一些分配本地值的操作。有关详细信息,请参阅 C# 规范的“明确分配”部分。 【参考方案1】:

是的,几乎是一回事。

你可以参考这篇文章Coding Horror

【讨论】:

【参考方案2】:

这里的各种回复都具有误导性,包括“编码恐怖”网站中引用的文章。

当配置为优化生成的代码时,编译器将优化您的代码以删除所有“不必要的”初始化。请注意,这是在“发布”模式下编译时的默认行为。

首先,我认为初始化所有变量总是非常有用的。在调试模式下对性能的影响最小,在发布模式下不会受到影响,但是显式设置变量的好处对于将来维护代码的任何人来说都是巨大的,采用更好的“用代码记录代码”风格。我记得我这个非常有经验的同事认为 Int32 的默认值是 Int32.MinValue 而不是 0。这些类型的混淆总是发生在代码中隐含的事情上,对我来说,在大多数情况下应该避免它们。

【讨论】:

【参考方案3】:

说了这么多,值得一提的是 C# 中的“default”关键字。

int i; 相当于 int i = default(int); 相当于 int i = 0;MyClass o = default(MyClass); 等价于MyClass o = null;

这在使用诸如.SingleOrDefault() 之类的 linq 方法时尤其重要,因为您始终可以使用以下内容使您的代码更具可读性:

int someValue = collection.<various linq methods>.SingleOrDefault();
if (someValue == default(int))

  //Code for the default case

MyClass someValue = collection.<various linq methods>.SingleOrDefault();
if (someValue == default(MyClass))

  //Code for the default case

【讨论】:

【参考方案4】:

如果变量i是一个实例变量,它会被自动赋值为0。如果它是方法中的局部变量,则它是未定义的,因此您需要在使用它之前为其分配一个值。

例如:

class Program

    static void Main(string[] args)
    
        intTest it;

        it = new intTest();

        Console.ReadLine();
    

    class intTest
    
        int i;

        public intTest()
        
            int i2;

            Console.WriteLine("i = " + i);
            Console.WriteLine("i2 = " + i2);
        
    

上面的代码不会编译,因为 i2 没有赋值。但是,通过将 0 分配给 i2,即

int i2 = 0;

编译,然后运行,将显示现在两者都分配了 0。

【讨论】:

int 是一个结构而不是一个类。结构有一个默认值,而类默认为空。 @Matthew Whited,他并不是说这是一堂课。他说的是“级别”类,这实际上意味着实例变量。我对其进行了编辑以进行澄清。【参考方案5】:

这些仅对字段(类变量)等效。初始化类时,字段会自动分配默认值。在方法或属性中,未分配的变量保持未分配状态,如果您尝试访问它的值,将导致编译器错误。

【讨论】:

【参考方案6】:

我查看了 IL(使用 ildasm),确实只有 int 设置为 0 才真正在构造函数中设置为 0。

public class Class1

    int setToZero = 0;
    int notSet;

生成:

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed

  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  stfld      int32 ClassLibrary1.Class1::setToZero
  IL_0007:  ldarg.0
  IL_0008:  call       instance void [mscorlib]System.Object::.ctor()
  IL_000d:  nop
  IL_000e:  ret
 // end of method Class1::.ctor

【讨论】:

但是该类的 ctor 是否有可能为那些未显式分配的变量处理变量初始化? Michael:字段由内存管理器初始化为默认(零)值,而不是由构造函数 非常感谢 Eric Lippert 的澄清。我希望我能对参与此讨论的一个或多个个人表示赞赏。像往常一样,我总是带着更多的知识离开;)【参考方案7】:

每当您在 C# 中创建类型时,它都会自动填充零。在类(引用类型)的情况下,这等同于空指针。因此,从技术上讲,任何时候使用类,以下内容都是相同的:

MyClass class;
MyClass class2 = null;

对于值类型(任何结构,包括 int/float/double/etc),类型以零传递,因此以下是等价的:

int i;
int j = 0;

但是,在一个方法中,编译器会在使用之前检查您是否为类型分配了一个值。如果您执行以下操作,编译器会报错:

int i;
Console.WriteLine"0",i);

从技术上讲,上面应该没问题 - 但由于它是程序员错误的常见来源,编译器专门检查未分配的局部变量并抱怨。但是,这是编译时投诉,而不是 CLR 问题。您可以制作完成上述操作的 IL,并且它运行良好。

【讨论】:

【参考方案8】:

正如以下链接所述,它们完全相同:

http://msdn.microsoft.com/en-us/library/aa664742%28VS.71%29.aspx

【讨论】:

仅当它们是字段(类成员)时才为真。 OP 提到了变量,名称也暗示了这一点。

以上是关于C# 变量初始化问题的主要内容,如果未能解决你的问题,请参考以下文章

C#成员变量初始化;最佳实践?

c++、java、C#之间的for循环初始化变量范围

C#变量初始化问题:字段初始值无法引用非静态字段方法或属性

[C#]变量初始化问题:字段初始值无法引用非静态字段方法或属性

C# 内存模型和非易失性变量在其他线程创建之前初始化

C#类的初始化顺序