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

C# 如何使Unity单例基类支持泛型?,c#,generics,unity3d,unity5,C#,Generics,Unity3d,Unity5,在我的项目中,我有一个类结构,如图所示 绿色类是旧代码,运行得很好。红色框中的类是新添加的代码。没有编译器错误,但是当在Unity中单击play并运行到新代码中时,这三个类无法正确初始化 unity console发出警告说“名为'DataMgrBase`2'的类是泛型的。不支持泛型单行为!UnityEngine.GameObject:AddComponent()”在这一行:“instance=obj.AddComponent();” 我怎样才能解决这个问题 以下是一些代码供您参考,谢谢 单例基

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

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

unity console发出警告说“名为'DataMgrBase`2'的类是泛型的。不支持泛型单行为!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);
        }
    }
}
使用UnityEngine;
使用系统集合;
公共类UnitySingletonPersistent:MonoBehavior,其中T:Component
{
私有静态T实例;
公共静态T实例{
得到{
if(实例==null){
instance=FindObjectOfType();
if(实例==null){
gameobjectobj=新的GameObject();
obj.name=类型(T).name;
obj.hideFlags=hideFlags.DontSave;
instance=obj.AddComponent();
}
}
返回实例;
}
}
公共虚拟空唤醒()
{
DontDestroyOnLoad(this.gameObject);
if(实例==null){
实例=此为T;
}否则{
摧毁(游戏对象);
}
}
}
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);
        }
    }    
}
公共类DataMgrBase:UnitySingletonPersistent{
受保护字典数据字典;
公共覆盖无效唤醒()
{
base.Awake();
dataDict=新字典();
}
公共TValue GetDataForKey(TKey)
{
价值数据;
if(DATADECT.TryGetValue(键,输出数据))
{
返回数据;
}
其他的
{
数据=LoadDataForKey(键);
如果(数据!=null)
{
添加(键,数据);
}
返回数据;
}
}
虚拟受保护的TValue LoadDataForKey(TKey)
{
if(数据目录容器(键))
{
返回GetDataForKey(键);
}
其他的
{
返回默认值(TValue);
}
}    
}

您想要的是:

public abstract class UnitySingletonPersistent<T> : MonoBehaviour where T:UnitySingletonPersistent<T>
{
...
}
公共抽象类UnitySingletPersistent:MonoBehavior,其中T:UnitySingletPersistent
{
...
}
然后在你的具体课程中:

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

这是一个无法解决问题的答案,但可以解释问题

monobhavior
不能为泛型,至少有两个原因:

1。假设您想在Unity3D编辑器的Inspector中添加通用组件。现在引擎需要准确地知道这个组件中的所有类型,这不仅是因为它将在这一刻被编译,而且还因为您可能拥有具有未记录类型的公共字段。尝试直接在Inspector中分配您的
UnitySingletonPersistent
,您会发现这是不可能的

2.
T
为通用的情况下使用
AddComponent
看起来可以工作,但在这个引擎中,你可以用实例化的游戏对象制作所谓的预制,如果这个游戏对象包含通用组件Unity3D引擎需要支持某种烘焙类型,在实践中,这将导致生成脚本,每个脚本都有不同的类型,并在项目内部造成混乱。我希望你跟我来

但为什么它适用于用绿色标记的组件?原因很简单,当将此组件添加到GameObject时,Unity3D引擎知道所有类型

为了支持所有这些Unity技术,需要对Unity3D引擎及其工作方式进行核心更改。它将使Unity3D完全不同于现在的引擎


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

我自己解决了这个问题,如下所示:

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

公共类DataMgrBase:UnitySingletonPersistent其中TClass:Component
对于要从中派生的所有其他三个类,请将它们更改为以下形式:

public class MobSettingDataMgr : DataMgrBase<int, MobSettingData, MobSettingDataMgr>
公共类MobSettingDataMgr:DataMgrBase

这与OP有什么不同?谢谢!试过了,还是一样的警告。在“instance=obj.AddComponent();”处初始化仍然失败,谢谢分享,但我已经解决了这个问题。请核对我的答案。编译后泛型类型不会改变,因此它实际上不是“运行时”泛型。这是一种很酷的解决方法,但我有一点感觉,它不是Unity3D的工作方式。不管怎样,恭喜你解决了这个问题!谢谢:)@JerrySwitalski
public class MobSettingDataMgr : DataMgrBase<int, MobSettingData, MobSettingDataMgr>