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;
}
我的思考过程让我相信:
- 应该有一个 ItemDatabase 实例,这反过来意味着只有一个列表需要管理。
- 由于 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
}
我正在为 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;
}
我的思考过程让我相信:
- 应该有一个 ItemDatabase 实例,这反过来意味着只有一个列表需要管理。
- 由于 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
}