C#中的非初始化变量

Sna*_*ake 17 .net c# variables initialization

我有以下代码:

class Foo
{

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

        }
    }
}

class Bar { }
Run Code Online (Sandbox Code Playgroud)

代码专家已经看到这会给出错误.在if语句之前可能没有初始化Bar.

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

Jon*_*eet 36

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

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

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

int i;
if (i == 0) // Nope, i isn't definitely assigned
{
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 它由方法元数据上的*​​localsinit*标志控制.有关详细信息,请参见第III部分3.47"localloc".我似乎记得CLR始终将堆栈内存初始化为零,无论如何.或者在附加调试器时它总是这样做?我不确定.无论如何,通过偷偷摸摸的方式观察到未初始化状态的当地人似乎总是有默认值. (7认同)

Mar*_*ell 8

字段(类/结构上的变量)初始化为null/ zero/etc.局部变量......好 - 因为(通过"明确的分配")你不能在没有分配的情况下访问它们,没有明智的回答方式; 简单地说,它没有被定义,因为它是不可能的.我相信它们碰巧null/ zero/etc(可以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);
    }
}
Run Code Online (Sandbox Code Playgroud)

IL 只是做了"退缩" - 它从不分配任何东西.

  • @Matt:这根本不是一个坏问题.我在这里讨论其中的一些问题:http://blogs.msdn.com/ericlippert/archive/2009/10/12/absence-of-evidence-is-not-evidence-of-absence.aspx但我不知道实际上回答你的具体问题.基本上:(1)当在写入字段之前显示字段可能被读取时,你更有可能得到"误报"错误.(2)编译器确实对从未写过或从未读过的字段发出警告(3) )与locals不同,字段有一个完整的方法 - 构造函数 - 专门用于初始化它们. (2认同)