[英]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.