繁体   English   中英

C#中未初始化的变量

[英]Noninitialized variable in C#

我有以下一段代码:

class Foo
{

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

        }
    }
}

class Bar { }

代码专家已经看到这会产生错误。 Bar可能不会在if语句之前初始化。

什么酒吧的价值? 不应该为空吗? 他们不是设置为空吗? (空指针?)

不,局部变量没有默认值1 在您阅读它们之前,必须明确分配它们。 这减少了您使用您认为已赋予合理值的变量的机会,而实际上它有一些默认值。 这不能用于实例变量或静态变量,因为您不知道方法将按什么顺序调用。

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

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

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

1就语言而言,无论如何......显然内存中的存储位置有一些东西,但它无关紧要且特定于实现。 一种方法可以找出该值是什么,通过创建一个带有out参数的方法,然后使用 IL 查看该方法中该参数的值,而无需为其赋予另一个值。 CLR 根本不介意。 然后,您可以调用该方法,传入一个不确定赋值的变量,瞧,您可以检测到该值 - 基本上很可能是“全零”值。

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

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


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

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只是做一个“ret”——它从不分配任何东西。

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

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

    }
}

局部变量没有分配默认值,甚至没有null

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

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

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

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

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

编译器不会让您使用未定义的值,它必须能够确定变量是否已初始化,然后才能使用它。

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

这无关紧要,因为任何实现 C# 的编译器都不应编译此类代码。

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

除了“正确性”之外,局部变量的初始化也与CLR的验证过程有关

有关更多详细信息,请参阅我对这个类似问题的回答: 为什么局部变量必须具有初始值?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM