繁体   English   中英

从泛型类继承,该类也继承自泛型单例

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


一般来说,习惯于为每个单独的类/类型使用一个脚本文件。

另外我会稍微改变你在ItemEquipment领域,比如

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

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