将 GameObject 转换回通用类型 <T>

Convert GameObject back to generic type <T>

我正在为 Unity 实现一个深度对象复制器。

我在这里找到了这个很棒的 serialization/deserialization 方法:

但是我遇到了 MonoBehaviour 对象的问题。如果类型是 GameObject,我需要使用 Instantiate 而不是序列化。所以我添加了一张支票:

if (typeof(T) == typeof(GameObject))
{
    GameObject clone = Instantiate(source as GameObject);
    T returnClone = clone as T;
    return returnClone;
}

我可以将源转换为游戏对象(使用 as),但是当我尝试反向执行时,它失败了

The type parameter T cannot be used with the as parameter because it does not have a class type constraint nor a 'class' constraint.

如果我尝试像这样投射它:

if (typeof(T) == typeof(GameObject))
{
    GameObject clone = Instantiate(source as GameObject);
    T returnClone = (T)clone;
    return returnClone;
}

Cannot convert GameObject to type T

我觉得我很接近,但我不能完全正确地选角。你知道我缺少什么才能让它工作吗?

如果我转换类型以符合错误仍然存​​在:

它不是很漂亮,但你可以强制编译器将先前的引用转换为 object:

 public static T Clone<T>(T source)
 {
      if (source is GameObject)
      {
          return (T)(object)Instantiate((GameObject)(object)source);  
      }
      else ...
  }

是的,这有点麻烦,但有时您无法避免。作为一般规则,当您开始将泛型与运行时类型检查混合使用时,事情往往会变得一团糟,这是您可能一开始就不应该使用泛型的明确信号。虽然有时候,它是合理的,但丑陋的代码往往会突然出现。

在 return 语句中使用 as T 似乎可以解决问题。在场景中附加到游戏对象的以下测试代码中,我看到 Test 的克隆,并且控制台显示 Count 的不同值:

public class Test : MonoBehaviour
{
    private static bool _cloned = false;

    public static T Clone<T>(T source) where T : class 
    {
        if (typeof(T) == typeof(GameObject))
        {
            GameObject clone = Instantiate(source as GameObject);
            return clone as T;
        }
        else if (typeof(T) == typeof(PlainType))
        {
            PlainType p = new PlainType();
            // clone code
            return p as T;
        }
        return null;
    }

    public class PlainType
    {
        private static int _counter = 0;
        public int Count = ++_counter;
        public string Text = "Counter = " + _counter;
    }

    public PlainType MyPlainType = new PlainType();

    void Update ()
    {
        if (!_cloned)
        {
            _cloned = true;
            Clone(gameObject);
            PlainType plainClone = Clone(MyPlainType);
            Debug.Log("Org = " + MyPlainType.Count + " Clone = " + plainClone.Count);
        }
    }

}