I am implementing a deep object copier for Unity.
I found this great serialization/deserialization method here: https://stackoverflow.com/a/78612/3324388
However I hit a snag with MonoBehaviour objects. If the type is a GameObject, I need to use Instantiate
instead of the serialization. So I've add a check:
if (typeof(T) == typeof(GameObject))
{
GameObject clone = Instantiate(source as GameObject);
T returnClone = clone as T;
return returnClone;
}
I am able to cast the source as a GameObject (using as
) but when I try to do it in reverse it fails with
The type parameter
T
cannot be used with theas
parameter because it does not have a class type constraint nor a 'class' constraint.
If I try just casting it like:
if (typeof(T) == typeof(GameObject))
{
GameObject clone = Instantiate(source as GameObject);
T returnClone = (T)clone;
return returnClone;
}
Cannot convert GameObject to type
T
I feel I'm close but I can't quite get the casting right. Do you know what I am missing to get this to work?
If I cast the type to conform the error still persists:
Using as T
in the return statement seems to do the trick. In the following test code attached to a game object in the scene I see a clone of Test
and the console shows me different values for 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);
}
}
}
It’s not pretty but you can force the compiler doing a previous reference conversion to object
:
public static T Clone<T>(T source)
{
if (source is GameObject)
{
return (T)(object)Instantiate((GameObject)(object)source);
}
else ...
}
Yes, it is a bit of hack but sometimes you can’t avoid it. As a general rule, when you start mixing generics with runtime type checks things tend to get messy, a sure sign that you probably shouldn’t be using generics to begin with. Sometimes though, it can be justified but ugly code tends to crop up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With