So I’m aware that for ScriptableObject.CreateInstance to work, ‘T’ can’t remain generic.
I have the following code, in which ‘T’ is eventually made definite:
Abstract base class
public abstract class MouthSetGenericEditor<T> : Editor
{
public static void CreateMouthSet(T fillerResource)
{
var mouthset = ScriptableObjectUtility.CreateAsset<MouthSetGeneric<T>>();
}
}
Child class where type is made definite
[CustomEditor(typeof(MouthSetGeneric<Sprite>))]
public class MouthSetSpriteEditor : MouthSetGenericEditor<Sprite>
{
private static readonly Sprite placeholderSprite = Resources.Load<Sprite>("Placeholder");
[MenuItem("Assets/Rhubarb/Create Sprite Mouthset")]
public static void CreateSpriteMouthSet()
{
CreateMouthSet(placeholderSprite);
}
}
Utility where ScriptableObject.CreateInstance() is called
public static class ScriptableObjectUtility
{
public static T CreateAsset<T>() where T : ScriptableObject
{
T asset = ScriptableObject.CreateInstance<T>();
if (asset == null)
Debug.Log("asset null");
// more code...
}
}
In the same block where ScriptableObject.CreateInstance() is called, if I log typeof(T).ToString(), the console outputs MouthSetGeneric`1[UnityEngine.Sprite]. So it looks like type T was made definite, but the ScriptableObject instantiation call isn’t behaving as though it is.
Ok first of all you should know that Unity can not serialize generic types, at all. They made an explicit / hardcoded exception for the generic List class but any other generic class can not be serialized. Therefore you can not have a generic MonoBehaviour or ScriptableObject instance. However what you can do is create a derived (non generic) class from your generic class for each type parameter you want to use and use those classes instead.
The second thing that seems a bit strange is that you call your method “CreateAsset” which you want to call at runtime. Assets in the Unity word means serialized objects in the project. Assets can only be created in the editor and not at runtime. However instances of objects or even of assets can be made at runtime (That’s why the method is called CreateInstance).
It’s not clear what you want to do here. If you want to create a clone / copy of an asset, just use Instantiate. You can instantiate scriptable object instances / assets just like any other object derived from UnityEngine.Object.
Finally while it is true that the generic type parameters are always bound at runtime, in normal C# the type parameters is actually fix at compile time based on the usage. C# doesn’t have a special variable type for type parameters. Types are given in code. In your example you have defined a concrete class of your abstract editor class which you called “MouthSetSpriteEditor” and the generic type parameter is filled with the type Sprite.
While it is possible to actually bind the type parameter dynamically using reflection in order to generate a new type, however this is generally not the way to go and isn’t supported at AOT platforms like iOS since it requires JIT compiling as you would create a new unknown type at runtime.
Finally keep in mind that when you use a generic class with two different types as T, those two generated concrete classes do not have anything in common in the sense of OOP. A List<int> and a List<string> are two seperate classes which happens to be created by the same generic class List<T> but are completely seperate class types which can’t interact in any way. It’s like the difference between public class A {} and public class B {}. Even though .NET generics work completely different from C++ templates, the basic idea is the same. The generic class is not an abstraction in the OOP sense but more a generic template for different implementations.
Keep in mind we only see a fraction of the whole picture of your case. We don’t know how this code is supposed to work and what the end result should look like. If you want to create some sort of factory, I’m afraight this isn’t going to work since as i said at the top Unity doesn’t support the serialization of generic types at all. At least up to this point in time ^^.