【问题标题】:Convert GameObject back to generic type <T>将 GameObject 转换回泛型类型 <T>
【发布时间】:2018-06-11 14:24:23
【问题描述】:

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

我在这里找到了这个很棒的序列化/反序列化方法:https://stackoverflow.com/a/78612/3324388

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

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

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

类型参数T 不能与as 参数一起使用,因为 它没有类类型约束,也没有“类”约束。

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

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

无法将 GameObject 转换为类型 T

我觉得我很接近,但我不能完全正确地选择演员。你知道我缺少什么让这个工作吗?

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

【问题讨论】:

  • return Instanciate(...) ?投射到 T 没有意义
  • 在这种情况下我得到这个错误:[错误]泛型类型中的类型T' cannot be used as type parameter T'或方法UnityEngine.Object.Instantiate&lt;T&gt;(T)'. There is no boxing or type parameter conversion from T'到`UnityEngine.Object'
  • 听起来你需要约束T,无论你在哪里声明它(你没有显示)就像class MyClass&lt;T&gt; where T : GameObject { ... }
  • 是的,我曾想过,但这将限制它不适用于非游戏对象的混合对象
  • 然后进行约束where T : class.

标签: c# unity3d serialization deserialization deep-copy


【解决方案1】:

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

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

是的,这有点小技巧,但有时你无法避免。作为一般规则,当您开始将泛型与运行时类型检查混合时,事情往往会变得混乱,这是您可能不应该从一开始就使用泛型的明确迹象。有时,这是有道理的,但丑陋的代码往往会突然出现。

【讨论】:

  • 有效,但我更喜欢 Kay 回答中的return p as T; 解决方案。
  • 我想弄清楚你是怎么想出来的,但我画了一个空白。荣誉。这行得通。
  • @Draco18s 哎呀抱歉,忘记删除 class 约束。这适用于任何类型。
【解决方案2】:

在 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);
        }
    }

}

【讨论】:

  • 这确实排除了克隆任何值类型,但如果这不是问题,它绝对比object 的中间转换更干净、更漂亮。 @Aggressor
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
相关资源
最近更新 更多