[英]Inheriting from generic class that also inherits from a generic singleton
我很难从泛型类继承,而泛型类本身是从泛型单例继承的。
我正在尝试制作一个单件库存基类,并从中使用不同的派生项目派生出不同的库存类型。
为简洁起见,代码已被简化。
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static bool m_ShuttingDown = false;
private static object m_Lock = new object();
private static T m_Instance;
public static T Instance
{
get
{
if (m_ShuttingDown)
return null;
lock (m_Lock)
{
if (m_Instance == null)
{
m_Instance = (T)FindObjectOfType(typeof(T));
if (m_Instance == null)
{
var singletonObject = new GameObject();
m_Instance = singletonObject.AddComponent<T>();
singletonObject.name = typeof(T).ToString() + " (Singleton)";
DontDestroyOnLoad(singletonObject);
}
}
return m_Instance;
}
}
}
private void OnApplicationQuit()
{
m_ShuttingDown = true;
}
private void OnDestroy()
{
m_ShuttingDown = true;
}
}
public class Inventory<T> : Singleton<Inventory<T>> where T : Item
{
...
}
public class EquipmentInventory : Inventory<Equipment>
{
...
}
public class Item : ScriptableObject
{
public string Name = "Item";
}
public class Equipment : Item
{
public string Name = "Equipment";
}
我无法访问实例;
private EquipmentInventory equipmentInventory;
private Inventory<Item> inventory;
public void Run()
{
var cachedInventory = Inventory<Item>.Instance; //returns null
var cachedEquipmentInventory = EquipmentInventory.Instance as EquipmentInventory; //returns null
}
两个语句都返回 null。
这样做的目的是,每个库存类型都是一个单件,每种类型的库存将实现不同的项目类型,因此基础库存将使用项目类型,而设备库存将使用设备项目类型实现。
这是一种替代方法,它似乎解决了这个问题
public abstract class Inventory<T, TClass>
: Singleton<TClass> where TClass
: MonoBehaviour where T : Item
{
}
public class EquipmentInventory : Inventory<Equipment, EquipmentInventory>
{
}
我还没有用实际代码完全测试过这个,但是当我更彻底地测试它时会更新
请协助。
主要问题是由
public class Inventory<T> : Singleton<Inventory<T>> : where T : Item { }
在这里,您将泛型类型Iventory<T>
“传入”到Singleton
即使稍后您显式继承了该Inventory<T>
类。
这是一个可能的解决方案,尽管起初看起来有点奇怪:
使您的 Inventory 采用第二个泛型类型,根据需要在类中使用第一个,并将第二个“转发”到Singleton<T>
,例如
// Note how for the limitation via where you still can use the generic type
// which makes sure no other MonoBehaviour can be passed to TSelf by accident
public class Inventory<TItem, TSelf> : Singleton<TSelf> where TItem : Item where TSelf : Inventory<TItem,TSelf>
{
public TItem reference;
private void Awake()
{
if (!reference) reference = ScriptableObject.CreateInstance<TItem>();
}
}
然后在实现中,你的通行证另外在你自己的最终(非通用)类型中,所以它可以正确地“转发”到Singleton<T>
像例如
public class EquipmentInventory : Inventory<Equipment, EquipmentInventory> { }
请注意,无论如何,此类必须位于名为EquipmentInventory.cs
的单独文件中,否则它将无法作为 Unity 中的组件运行。
这现在有效,因为现在您显式传递了TSelf
EquipmentInventory
类型,然后将其转发到Signleton<T>
因此Instance
的返回类型明确为EquipmentInventory
。
一般来说,习惯于为每个单独的类/类型使用一个脚本文件。
另外我会稍微改变你在Item
和Equipment
领域,比如
[CreateAssetMenu]
public class Item : ScriptableObject
{
[SerializeField] private string _name;
public string Name => _name;
private void Awake()
{
_name = GetName();
}
protected virtual string GetName()
{
return nameof(Item);
}
}
和
[CreateAssetMenu]
public class Equipment : Item
{
protected override string GetName()
{
return nameof(Equipment);
}
}
这就是它的样子,例如
public class Example : MonoBehaviour
{
public EquipmentInventory equipmentInventory;
[ContextMenu("Run")]
public void Run()
{
equipmentInventory = EquipmentInventory.Instance;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.