簡體   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