如何使Unity单例基类支持泛型?

时间:2016-03-15 09:56:32

标签: c# generics unity3d unity5

classes deriving relations

在我的项目中,我有一个类结构,如图所示。

绿色类是旧代码,运行得非常好。红色框中的类是新添加的代码。没有编译器错误,但是当在Unity中单击播放并运行到新代码时,无法正确初始化这三个类。

Unity控制台发出警告说“名为'DataMgrBase`2'的类是通用的。不支持Generic MonoBehaviours!UnityEngine.GameObject:AddComponent()”在这一行:“instance = obj.AddComponent();”

我该如何解决这个问题?

以下是一些代码供您参考,谢谢!

单例基类的实现:

using UnityEngine;
using System.Collections;

public class UnitySingletonPersistent<T> : MonoBehaviour where T : Component
{
    private static T instance;

    public static T Instance {
        get {
            if (instance == null) {
                instance = FindObjectOfType<T> ();
                if (instance == null) {
                    GameObject obj = new GameObject ();
                    obj.name = typeof(T).Name;
                    obj.hideFlags = HideFlags.DontSave;
                    instance = obj.AddComponent<T> ();
                }
            }
            return instance;
        }
    }

    public virtual void Awake ()
    {
        DontDestroyOnLoad (this.gameObject);
        if (instance == null) {
            instance = this as T;
        } else {
            Destroy (gameObject);
        }
    }
}

DataMgrBase的实现:

public class DataMgrBase<TKey, TValue>: UnitySingletonPersistent<DataMgrBase<TKey, TValue>> {

    protected Dictionary<TKey, TValue> dataDict;

    public override void Awake()
    {
        base.Awake();

        dataDict = new Dictionary<TKey, TValue>();
    }

    public TValue GetDataForKey(TKey key)
    {
        TValue data;
        if (dataDict.TryGetValue(key, out data))
        {
            return data;
        }
        else
        {
            data = LoadDataForKey(key);
            if (data != null)
            {
                dataDict.Add(key, data);
            }

            return data;
        }
    }

    virtual protected TValue LoadDataForKey(TKey key)
    {
        if (dataDict.ContainsKey(key))
        {
            return GetDataForKey(key);
        }
        else
        {
            return default(TValue);
        }
    }    
}

3 个答案:

答案 0 :(得分:2)

我自己解决了以下问题:

更改基类以获取新的泛型类型(将从中派生的类,并将此类型传递给单例基类)

public class DataMgrBase<TKey, TValue, TClass>: UnitySingletonPersistent<TClass> where TClass: Component

对于想要从中派生的所有其他三个类,请按以下形式更改它们:

public class MobSettingDataMgr : DataMgrBase<int, MobSettingData, MobSettingDataMgr>

答案 1 :(得分:0)

你想要这样的东西:

public abstract class UnitySingletonPersistent<T> : MonoBehaviour where T:UnitySingletonPersistent<T>
{
...
}

然后在你的具体课堂上:

public class DataMgrBase<TKey, TValue> : UnitySingletonPersistent<DataMgrBase<TKey, TValue> >
{
...
}

答案 2 :(得分:0)

这是某种方式的答案,不是解决你的问题,而是解释问题。

MonoBehaviour至少有两个原因不能通用:

1. 想象一下,您想要从Unity3D编辑器中在Inspector中添加通用组件。现在引擎需要确切知道这个组件中的所有类型,不仅是casue它将在这一刻被编译,而且还会导致你可以拥有具有未清除类型的公共字段。尝试直接在Inspector中分配UnitySingletonPersistent,你会发现它是不可能的。

2。使用AddComponent<T>其中T是通用的看似可行,但在此引擎中,您可以使用实例化的GameObjects制作所谓的预制件,如果这样GameObject包含通用组件Unity3D引擎需要支持某种烘焙类型,并且在实践中这将导致生成脚本,每个脚本具有不同类型,并且在项目内部造成大混乱。我希望你能跟着我。

但为什么它适用于您用绿色标记的组件?只需使Unity3D引擎在将此组件添加到GameObject时就知道所有类型。

为了支持所有这些,Unity Technologies需要在Unity3D引擎中进行核心更改,现在它是如何工作的。这将使Unity3D完全不同于现在的引擎。

因此,要解决您的问题,只有一种方法:不添加运行时通用组件,并摆脱DataMgrBase类。因此,您需要在每个组件中实现DataMgrBase逻辑。