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

问题描述:

我正在开发一个项目系统的Unity,我想推理关于XML文件操作。我有一个ItemDatabase类,如下图所示:C#:访问静态类实例的初始化成员返回NULL

[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模式,这是有道理的,我使用了类似的数据库。类的实例是静态的,而列表在上面初始化。

但是,我然后尝试访问这个类,使用我称为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被初始化,我可以直接从外部类如管理器访问它。

但是,无论何时编辑器窗口出现,我都会收到一个空引用异常,表示项目列表为空。我已经确认它不是ItemDatabase实例。当List作为类定义的一部分被立即初始化时,它甚至有可能是空的?在这种情况下我基本忽略了什么?也许我错误地解释了构造函数的基本顺序?

假设我正确地理解了一些事情,将列表设置为公共静态修复程序 - 但它破坏了保持列表直接无法访问的目的?

+0

它的早期,所以也许我只是想念一些东西。你在哪里填充物品清单?仅仅基于你的代码,你永远不会用任何数据填充'itemDb.Items',所以它当然是空的。 – maccettura

+4

当你需要一个单例反序列化时,这是一种代码味道。不要这样做。 – dymanoid

+1

“它立即被初始化为类定义的一部分”,这是不正确的。 'Items'是一个实例字段,在您创建实例_时被初始化。您不会在客户端代码中的任何位置创建实例。 –

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

仅供参考您的单身模式的版本是_不线程safe_。 – maccettura

+0

@maccettura谢谢,我添加了一个简单的线程安全版本。 – aghidini

+0

技术上你的编辑仍然存在风险 – maccettura