简体   繁体   English

C#中未初始化的变量

[英]Noninitialized variable in C#

I have the following piece of code:我有以下一段代码:

class Foo
{

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

        }
    }
}

class Bar { }

Code gurus will already see that this gives an error.代码专家已经看到这会产生错误。 Bar might not be initialized before the if statement. Bar可能不会在if语句之前初始化。

What is the value of bar?什么酒吧的价值? Shouldn't it be null?不应该为空吗? Aren't they set to null?他们不是设置为空吗? (null pointer?) (空指针?)

No, local variables don't have a default value 1 .不,局部变量没有默认值1 They have to be definitely assigned before you read them.在您阅读它们之前,必须明确分配它们。 This reduces the chance of you using a variable you think you've given a sensible value to, when actually it's got some default value.这减少了您使用您认为已赋予合理值的变量的机会,而实际上它有一些默认值。 This can't be done for instance or static variables because you don't know in what order methods will be called.这不能用于实例变量或静态变量,因为您不知道方法将按什么顺序调用。

See section 5.3 of the C# 3.0 spec for more details of definite assignment.有关明确赋值的更多详细信息,请参阅 C# 3.0 规范的第 5.3 节。

Note that this has nothing to do with this being a reference type variable.请注意,这与 this 作为引用类型变量无关。 This will fail to compile in the same way:这将无法以相同的方式编译:

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

1 As far as the language is concerned, anyway... clearly the storage location in memory has something in it, but it's irrelevant and implementation-specific. 1就语言而言,无论如何......显然内存中的存储位置有一些东西,但它无关紧要且特定于实现。 There is one way you can find out what that value is, by creating a method with an out parameter but then using IL to look at the value of that parameter within the method, without having given it another value.一种方法可以找出该值是什么,通过创建一个带有out参数的方法,然后使用 IL 查看该方法中该参数的值,而无需为其赋予另一个值。 The CLR doesn't mind that at all. CLR 根本不介意。 You can then call that method passing in a not-definitely-assigned variable, and lo and behold you can detect the value - which is likely to be the "all zeroes" value basically.然后,您可以调用该方法,传入一个不确定赋值的变量,瞧,您可以检测到该值 - 基本上很可能是“全零”值。

I suspect that the CLI specification does enforce local variables having a default value - but I'd have to check.我怀疑 CLI 规范确实强制执行具有默认值的局部变量 - 但我必须检查。 Unless you're doing evil things like the above, it shouldn't matter to you in C#.除非你在做像上面那样的坏事,否则在 C# 中对你来说无关紧要。

Fields (variables on classes / structs) are initialized to null /zero/etc.字段(类/结构上的变量)被初始化为null /零/等。 Local variables... well - since (by "definite assignment") you can't access them without assigning there is no sensible way of answering;局部变量......好吧 - 因为(通过“明确赋值”)你不能在没有赋值的情况下访问它们,所以没有合理的回答方式; simply, it isn't defined since it is impossible.简单地说,它没有定义,因为它是不可能的。 I believe they happen to be null /zero/etc (provable by hacking some out code via dynamic IL generation), but that is an implementation detail.我相信他们碰巧null /零/等(由黑客一些可证明out通过动态IL代码),但是这是一个实现细节。


For info, here's some crafy code that shows the value of a formally uninitialised variable:有关信息,这里有一些疯狂的代码,显示了一个正式未初始化的变量的值:

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);
    }
}

The IL just does a "ret" - it never assigns anything. IL只是做一个“ret”——它从不分配任何东西。

Local variables do not get assigned a default value.局部变量不会被分配默认值。 You have to initialize them before you use them.您必须在使用它们之前初始化它们。 You can explicityly initialize to null though:您可以显式初始化为null

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

    }
}

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

No, local variables are not automatically set to 0 (default). 不,局部变量不会自动设置为0(默认值)。

But because you (always) get that error, it really doesn't matter. 但是因为你(总是)得到那个错误,所以无所谓。 If it had a another value the compiler would never let you find out. 如果它有另一个值,编译器永远不会让你发现。

Not to be confused with field variables (class members), they are initialized to their type's default value (0/null/false/...). 不要与字段变量(类成员)混淆,它们初始化为其类型的默认值(0 / null / false / ...)。

The value of bar is undefined. bar的值未定义。 There's space allocated for it on the stack, but the space isn't initialised to any value so it contains anything that happened to be there before.堆栈上为它分配了空间,但该空间未初始化为任何值,因此它包含之前碰巧存在的任何内容。

(The local variable might however be optimised to use a register instead of stack space, but it's still undefined.) (然而,局部变量可能被优化为使用寄存器而不是堆栈空间,但它仍然未定义。)

The compiler won't let you use the undefined value, it has to be able to determine that the variable is initialised before you can use it.编译器不会让您使用未定义的值,它必须能够确定变量是否已初始化,然后才能使用它。

As a comparison, VB does initialise local variables.作为比较,VB 确实初始化了局部变量。 While this can be practical sometimes, it can also mean that you unintenionally use a variable before you have given it a meaningful value, and the compiler can't determine if it's what you indended to do or not.虽然这有时是实用的,但它也可能意味着您在给它一个有意义的值之前无意中使用了一个变量,并且编译器无法确定它是否是您想要做的。

It doesn't matter because no such code should be compilable by any compiler that implements C#.这无关紧要,因为任何实现 C# 的编译器都不应编译此类代码。

If there was a default value, then it would be compilable.如果有默认值,那么它将是可编译的。 But there is none for local variables.但是局部变量没有。

Besides "correctness", local variable initialization is also related to the CLR's verification process .除了“正确性”之外,局部变量的初始化也与CLR的验证过程有关

For more details, see my answer to this similar question: Why must local variables have initial values?有关更多详细信息,请参阅我对这个类似问题的回答: 为什么局部变量必须具有初始值?

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

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