简体   繁体   English

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

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

I am developing an Item system for Unity and I am trying to reason about XML file manipulation. 我正在为Unity开发Item系统,并试图推理XML文件操作。 I have an ItemDatabase class as shown below: 我有一个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;
            }
        }

    }

}

Recently, I got exposed to a very basic implementation of the Singleton pattern, which makes sense for me to use for something like a database. 最近,我接触到了Singleton模式的一个非常基本的实现,这对我来说可以用于数据库之类的东西。 The instance of the class is static, whereas the List is initialized above. 该类的实例是静态的,而List是在上面初始化的。

However, I then try to access this class using a GUI I called the DatabaseManager class. 但是,然后,我尝试使用称为DatabaseManager类的GUI访问此类。 The relevant implementation is shown below: 相关实现如下所示:

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

My thought process led me to believe that: 我的思想过程使我相信:

  1. There shall be one instance of ItemDatabase, which in turn implies there will only be one list to manage. 必须有一个ItemDatabase实例,这又意味着只有一个列表要管理。
  2. Since the List is initialized, I would be able to directly access it from external classes such as the manager. 由于列表已初始化,因此我可以从外部类(例如管理器)直接访问它。

However, whenever the editor window shows up, I get a Null Reference Exception, indicating that the List of items is null. 但是,每当出现编辑器窗口时,我都会收到Null Reference Exception,表示项目列表为null。 I have confirmed it is not the ItemDatabase instance. 我已经确认这不是ItemDatabase实例。 How is it even possible for the List to be empty when it was immediately initialized as part of the class definition? 立即将List初始化为类定义的一部分时,List怎么可能为空? What am I fundamentally overlooking in this scenario? 在这种情况下,我从根本上忽略了什么? Maybe there is an underlying order of constructors that I am misinterpreting? 也许我误解了构造函数的基本顺序?

Assuming I understand things properly, setting the list to public static fixes that - but it defeats the purpose of keeping the list directly inaccessible? 假设我理解得正确,将列表设置为public static可以解决-但这违背了使列表直接不可访问的目的吗?

Actually you are not implementing the singleton pattern correctly because you create the instance in the constructor. 实际上,由于在构造函数中创建了实例,因此您没有正确实现单例模式。 Have a look at this MSDN article . 看看这篇MSDN文章

Example: 例:

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
}

You can now simply access the singleton with: 现在,您可以使用以下命令简单地访问单例:

ItemDatabase.Instance

and the instance will be dynamically created on demand at the first access. 实例将在首次访问时根据需要动态创建。

EDIT: as per @maccettura comment the code above is not thread safe. 编辑:根据@maccettura注释,上面的代码不是线程安全的。 If you need thread-safety you can use a lock object ( 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM