C#:访问静态类实例的初始化成员返回NULL

时间:2017-09-19 14:53:58

标签: c# unity3d singleton nullreferenceexception

我正在为Unity开发一个Item系统,我正试图推理XML文件操作。我有一个ItemDatabase类,如下所示:

[XmlRoot("ItemDatabase")]
public class ItemDatabase
{
    // List that contains all Game Items.
    // Members must be Serializable. Use Editor workflow
    // to create an item Adder/Remover for the Database.
    [XmlArray("Items"), XmlArrayItem("BaseGameItem")]
    public List<BaseGameItem> Items = new List<BaseGameItem>();

    // Singleton Pattern. Only one instance will be initialized.
    public static ItemDatabase itemDb;

    public ItemDatabase()
    {
        if(itemDb == null)
        itemDb = this;
    }

    // Saves the Item List to an XML file.
    public void Save(string filepath)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ItemDatabase));

        // Disposable Pattern
        using (FileStream stream = new FileStream(filepath, FileMode.Create))
        {
            // Check if path was valid.
            if (stream != null)
            {
                serializer.Serialize(stream, this);
                stream.Close();
            }
        }
    }

    // Loads an existing Item List from an XML file.
    public static ItemDatabase Load(string filepath)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ItemDatabase));

        using (FileStream stream = new FileStream(filepath, FileMode.Open))
        {
            if (stream != null)
            {
                ItemDatabase db = serializer.Deserialize(stream) as ItemDatabase;
                stream.Close();
                return db;
            }

            // Return null if the file cannot be read/found.
            else
            {
                return null;
            }
        }

    }

}

最近,我接触到了Singleton模式的一个非常基本的实现,这对我来说有意义用于像数据库这样的东西。该类的实例是静态的,而List在上面初始化。

然而,我尝试使用名为DatabaseManager类的GUI访问此类。相关实施如下所示:

public class ItemDatabaseManager : EditorWindow
{
    // List of items from database.
    List<BaseGameItem> items;

    // Item template to add/remove from database.
    // To be filled by user.
    BaseGameItem itemToAdd;

    private void OnEnable()
    {
        items = ItemDatabase.itemDb.Items;
    }

我的思维过程让我相信:

  1. ItemDatabase应该有一个实例,这反过来意味着只有一个列表需要管理。
  2. 由于List已初始化,我可以直接从外部类(如经理)访问它。
  3. 但是,每当编辑器窗口出现时,我都会得到一个Null Reference Exception,表明项目列表为空。我已经确认它不是ItemDatabase实例。当List作为类定义的一部分立即初始化时,它怎么可能是空的?在这种情况下,我从根本上忽略了什么?也许我误解了构造函数的基本顺序?

    假设我正确理解了事情,将列表设置为公共静态修复 - 但它违背了保持列表不可访问的目的?

1 个答案:

答案 0 :(得分:1)

实际上,您没有正确实现单例模式,因为您在构造函数中创建了实例。 看看this MSDN article

示例:

public class ItemDatabase
{
   private static ItemDatabase _instance;

   private ItemDatabase() {}

   public static ItemDatabase Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new ItemDatabase();
         }
         return instance;
      }
   }

   // ... add the rest of your code
}

您现在可以通过以下方式访问单身人士:

ItemDatabase.Instance

,实例将在第一次访问时按需动态创建。

编辑:根据@maccettura评论,上面的代码是线程安全。如果您需要线程安全,可以使用锁定对象(see this article for more info):

public class ItemDatabase
{
   private static ItemDatabase _instance;
   private static readonly object _lock = new object();

   private ItemDatabase() {}

   public static ItemDatabase Instance
   {
      get 
      {
         lock (_object)
         {
             if (instance == null)
             {
                instance = new ItemDatabase();
             }
             return instance;
         }
      }
   }

   // ... add the rest of your code
}