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;
}
我的思维过程使我相信:
- 应有ItemDatabase,这又意味着只会有一个列表来管理的一个实例。
- 由于List被初始化,我可以直接从外部类如管理器访问它。
但是,无论何时编辑器窗口出现,我都会收到一个空引用异常,表示项目列表为空。我已经确认它不是ItemDatabase实例。当List作为类定义的一部分被立即初始化时,它甚至有可能是空的?在这种情况下我基本忽略了什么?也许我错误地解释了构造函数的基本顺序?
假设我正确地理解了一些事情,将列表设置为公共静态修复程序 - 但它破坏了保持列表直接无法访问的目的?
其实你没有正确实现单例模式,因为你在构造函数中创建了实例。 看看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
}
仅供参考您的单身模式的版本是_不线程safe_。 – maccettura
@maccettura谢谢,我添加了一个简单的线程安全版本。 – aghidini
技术上你的编辑仍然存在风险 – maccettura
它的早期,所以也许我只是想念一些东西。你在哪里填充物品清单?仅仅基于你的代码,你永远不会用任何数据填充'itemDb.Items',所以它当然是空的。 – maccettura
当你需要一个单例反序列化时,这是一种代码味道。不要这样做。 – dymanoid
“它立即被初始化为类定义的一部分”,这是不正确的。 'Items'是一个实例字段,在您创建实例_时被初始化。您不会在客户端代码中的任何位置创建实例。 –