C#:访问静态 class 实例 returns NULL 的初始化成员

C#:Accessing initialized member of static class instance returns NULL

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

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

    }

}

最近,我了解了单例模式的一个非常基本的实现,这对我来说很适合用于数据库之类的东西。 class的实例是静态的,而List是上面初始化的。

但是,我随后尝试使用名为 DatabaseManager class 的 GUI 访问此 class。相关实现如下图:

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 已初始化,我将能够从外部 class 直接访问它,例如管理器。

但是,每当编辑器 window 出现时,我都会收到空引用异常,表明项目列表为空。我已经确认它不是 ItemDatabase 实例。当 List 作为 class 定义的一部分立即初始化时,它怎么可能为空?在这种情况下,我从根本上忽略了什么?也许我误解了构造函数的基本顺序?

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

实际上你没有正确实现单例模式,因为你在构造函数中创建了实例。 看看 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
}