C#中的非初始化变量

时间:2010-03-25 13:23:31

标签: c# .net variables initialization

我有以下代码:

class Foo
{

    public Foo()
    {
        Bar bar;
        if (null == bar)
        {

        }
    }
}

class Bar { }

代码大师已经看到这会产生错误。在if语句之前可能没有初始化Bar。

所以现在我想知道:酒吧的价值是什么,不应该是空的吗?它们不是设置为空吗? (nullpointer?)

8 个答案:

答案 0 :(得分:35)

不,局部变量没有默认值 1 。在阅读之前,他们必须明确分配。这样可以减少使用你认为你给出了合理值的变量的可能性,当它实际上有一些默认值时。这不能用于实例或静态变量,因为您不知道将调用方法的顺序。

有关明确赋值的详细信息,请参阅C#3.0规范的第5.3节。

请注意,这与作为引用类型变量无关。这将无法以相同的方式编译:

int i;
if (i == 0) // Nope, i isn't definitely assigned
{
}

1 就语言而言,无论如何......显然内存中的存储位置中包含某些内容,但它不相关且与实现无关。通过创建一个带有out参数的方法,然后使用IL来查看方法中该参数的值,有一种方法可以找出该值是什么,而无需给它另一个价值。 CLR根本不介意。然后,您可以调用该方法传入一个非明确赋值的变量,并且看到您可以检测到该值 - 这可能基本上是“全零”值。

我怀疑CLI规范 强制执行具有默认值的局部变量 - 但我必须检查。除非你像上面那样做了邪恶的事情,否则在C#中对你来说无关紧要。

答案 1 :(得分:8)

字段(类/结构上的变量)初始化为null /零/等。局部变量......好 - 因为(通过“明确的分配”)你不能在没有分配的情况下访问它们,没有明智的回答方式;简单地说,它没有被定义,因为它是不可能的。我相信他们发生null /零/等(可以通过动态IL生成来攻击一些out代码来证明),但这是一个实现细节。


有关信息,这里有一些狡猾的代码,显示了一个正式未初始化的变量的值:

using System;
using System.Reflection.Emit;
static class Program
{
    delegate void Evil<T>(out T value);
    static void Main()
    {
        MakeTheStackFilthy();
        Test();
    }
    static void Test()
    {
        int i;
        DynamicMethod mthd = new DynamicMethod("Evil", null, new Type[] { typeof(int).MakeByRefType()});
        mthd.GetILGenerator().Emit(OpCodes.Ret); // just return; no assignments
        Evil<int> evil = (Evil<int>)mthd.CreateDelegate(typeof(Evil<int>));
        evil(out i);
        Console.WriteLine(i);
    }
    static void MakeTheStackFilthy()
    {
        DateTime foo = new DateTime();
        Bar(ref foo);
        Console.WriteLine(foo);
    }
    static void Bar(ref DateTime foo)
    {
        foo = foo.AddDays(1);
    }
}

IL 只是执行“撤销” - 它从不分配任何内容。

答案 2 :(得分:2)

不会为局部变量分配默认值。您必须在使用它们之前初始化它们。您可以明确地初始化为null

public Foo()
{
    Bar bar = null;
    if (null == bar)
    {

    }
}

答案 3 :(得分:1)

本地变量未分配默认值,甚至不是null

答案 4 :(得分:1)

不,局部变量不会自动设置为0(默认值)。

但是因为你(总是)得到那个错误,所以无所谓。如果它有另一个值,编译器永远不会让你发现。

不要与字段变量(类成员)混淆,将 初始化为其类型的默认值(0 / null / false / ...)。

答案 5 :(得分:1)

bar的值未定义。在堆栈上为它分配了空间,但空间没有初始化为任何值,因此它包含之前碰巧存在的任何内容。

(但是局部变量可能会被优化为使用寄存器而不是堆栈空间,但它仍未定义。)

编译器不允许您使用未定义的值,它必须能够在您使用它之前确定该变量已初始化。

作为比较,VB确实初始化局部变量。虽然这有时候是实用的,但它也可能意味着你在给它一个有意义的值之前无意中使用了一个变量,并且编译器无法确定它是否是你所做的那样。

答案 6 :(得分:0)

没关系,因为任何实现C#的编译器都不应该编译这样的代码。

如果有默认值,那么它将是可编译的。但是局部变量没有。

答案 7 :(得分:0)

除“正确性”外,局部变量初始化还与CLR的验证过程有关。
有关详细信息,请参阅我对此类似问题的回答:Why must local variables have initial values