簡體   English   中英

初始化容器時C#中的NullReferenceException

[英]NullReferenceException in C# when the container is initialized

在下面列出的C#代碼中,出現錯誤“ NullReferenceException”:

“你調用的對象是空的”

我猜該錯誤與繼承和/或模板定義有關。 該列表已初始化,在調試時,我可以確認該列表未指向NULL。 我不知道該怎么做。 (對不起的類名/結構很抱歉)。 例外發生在這里:this.localSMT.doSomething(base.list);

public class VTEST<V>
{
    public List<V> list;
    public LocalSMT<V> localSMT;
    public VTEST()
    {
        list = new List<V>();
    }
}
public class VTEST_FSUB<V> : VTEST<V>
{
    public VTEST_FSUB()
    {
        do_virtual();
    }
    public void do_virtual()
    {
        this.localSMT.doSomething(base.list);
    }
}
public class VTEST_RUN : VTEST_FSUB<int>
{
    public VTEST_RUN()
    {
        localSMT = new VTEST_SUB();
    }
}

public class LocalSMT<V>
{
    public LocalSMT() { }
    public virtual void doSomething(List<V> value) { }
}
public class VTEST_SUB : LocalSMT<int>
{
    public VTEST_SUB(){}
    public override void doSomething(List<int> value) { 
            System.Console.WriteLine("VTEST_SUB VIRTUAL");
    }
}
class Program 
{

    Program() {}

    static void Main(string[] args)
    {
        VTEST_RUN run = new VTEST_RUN();
    }
}

問題在於, VTEST_FSUB<V>構造函數主體在VTEST_RUN構造函數主體之前執行。 所以,當do_virtual被調用時, localSMT仍然是空。 然后do_virtual嘗試在localSMT上調用方法,因此是異常。

基本上,層次結構中任何類的初始化順序為:

  • 在聲明時初始化在初始化程序中聲明的變量(其他任何變量都具有變量類型的默認值)
  • 鏈接到基類初始化
  • 執行構造函數主體

有關更多詳細信息,請參見我有關構造函數鏈接的文章

經驗教訓:

  • 避免公共場所。 如果使用私有字段,則很容易找到讀取和寫入它們的每一段代碼
  • 理想情況下,請使用readonly字段:如果您將值沿構造函數鏈傳遞並在VTEST<V>構造函數中進行設置,則不會有問題。 (由於下一點, readonly字段仍然很readonly ...)
  • 避免在構造函數中調用虛擬方法。 在這種情況下,這不是問題,但是如果do_virtualVTEST_FSUB<V>是抽象的,並且可以重寫以在VTEST_RUN調用localSMT.doSomething ,則很容易遇到相同的問題。 它在構造函數主體運行之前仍會執行,這令人驚訝。 您在構造函數中調用的所有內容都在部分初始化的對象上進行操作,這是一個不穩定的情況。
  • 避免大型繼承層次結構。 與他們一起工作是很痛苦的事情,也是他們的理由。
  • 請遵循.NET命名約定! 您的代碼在某種程度上很難讀,因為它是如此獨特。 即使只提供示例代碼,也至少要遵循大寫約定。

嘗試:

public void do_virtual()
{
    localSMT=new LocalSMT<V>();
    localSMT.doSomething(list);
}

public class VTEST_FSUB<V> : VTEST<V>

在使用之前,您沒有實例化localSMT,所以它不起作用。

編輯:或

public class VTEST<V>
{
    public List<V> list;
    public LocalSMT<V> localSMT;
    public VTEST()
    {
        list = new List<V>();
        localSMT = new LocalSMT<V>();
    }
}

最好在構造函數中對其進行初始化。

第二個解決方案是更清潔。

public class VTEST_RUN : VTEST_FSUB<int>
{
   public VTEST_RUN()
   {
    localSMT = new VTEST_SUB();  // BAD!  localSMT isn't initialized yet!
    }
}

我相信您未能new您的對象之一:

public void do_virtual()
{
   localSMT = new LocalSMT<V>();
   localSMT.doSomething(list);
}

請確保在嘗試使用對象時對其進行初始化 不必擔心,這是編碼中非常普遍的問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM