Hello,
Since with Unity 2020.1 we’re now able to serialize generic types, I was wondering if its possible to make the ScriptableObject.CreateInstance<GenericScriptableObject<...>()> works too in order to not to have to implement a non-generic class before.
For exemple I have,
public class Variable<T> : ScriptableObject
{
private T _value = default;
public T Value
{
get => _value;
set => SetValue(value);
}
public void SetValue(T value)
{
_value = value;
}
}
and I want to be able to do
public Variable<float> floatVariable;
void Start()
{
floatVariable = ScriptableObject.CreateInstance<Variable<float>>();
}
(For now ScriptableObject.CreateInstance<Variable>() just returns null)
Thanks !
As far as I know you can achieve that via an static method on Variable class.
public class Variable<T> : ScriptableObject {
public static Variable<T> Create<U>(UArgs args) where U : Variable<T>{
var instance = ScriptableObject.CreateInstance<U>();
//modify and init instance
return instance;
}
}
@print_helloworld Why did you suggest this? Is there anything in the changelog that made you think it is possible in 20.2?
I investigated this a bit. The fact that CreateInstance() returns null is not the biggest obstacle. In the end, we can construct an empty scriptable object asset manually.
When you create a Variable script and select it in Unity, the inspector says “No MonoBehaviour scripts in the file, or their names do not match the file name”. But we can’t rename the file to “Variable.cs”, it is the OS limitation. Variable1.cs doesn't help either. So, Unity must allow naming generic UnityEngine.Object classes to something like "Name1.cs" on their C++ backend; only this way we will be able to create generic ScriptableObjects.
For testing purposes, can you add the component via editor scripting and check if it works? I’m wondering whether it’s just an Inspector related issue.
@Peter77 Since we are talking about ScriptableObjects here, I’m not sure I understood the “add the component” part right. Nevertheless, I created a generic MonoBehaviour like this:
public class GenericMonoBehaviour<T> : MonoBehaviour
{
[SerializeField] private T field;
}
And added it as a component via another script: var component = gameObject.AddComponent<GenericMonoBehaviour<string>>();
The result is in the attached image. Also, AddComponent() returned null.
My bad, I wasn’t aware it’s about ScriptableObject.
Thanks for testing with a MonoBehavior, that’s what I meant. Would be interesting to see if any magic method in that MonoBehavior, such as Awake/Start/Update etc, is called. If these are not called, I assume it’s more than an Inspector issue and “allow naming generic” isn’t the main culprit.
@Peter77 I tried adding a non-generic MonoBehaviour with a wrong file name via a script, and it was added successfully. I didn’t know it was possible, thanks for hinting at it!
As for the generic MonoBehaviour, no event methods were called upon its creation (I also added the [ExecuteAlways] attribute just in case). In the end, it’s not the naming problem. I think Unity just doesn’t support UnityEngine.Object-derived generic classes yet. It would be cool to see this in the near future.
I’m in dire need of this feature and I can’t understand why this isn’t possible. I guess it has to do with unity objects being partly written in native code like @Bunny83 says here. I think @SolidAlloy is right.
Is there a place where I can throw unity a suggestion directly? I’ve been struggling for weeks because of stuff like this not being properly ironed out. There’s not even any acknowledgement from Unity in the documentations that this isn’t possible.
This topic got me interested, and I created a proof-of-concept package that allows creating generic scriptable objects: Generic Unity Objects
What you can do with it:
Implement your own generic ScriptableObjects (e.g. Generic).
Create them from a context menu (similarly to the [CreateAssetMenu] attribute) and choose the generic argument type in the process.
Create object fields for generic ScriptableObjects and drag-and-drop the created assets to those fields.
Instantiate generic ScriptableObjects from scripts (but see the limitations.)
How does it work?
It generates a concrete ScriptableObject class for each asset with unique generic arguments you create. That is, when you create an asset of Generic, it creates the Generic_Int : Generic { } class. It then uses the concrete type to instantiate a generic scriptable object when you call GenericScriptableObject.CreateInstance<Generic>()
Your code should only know of Generic but there will be a backing concrete class under the cover.
I will appreciate any feedback. Hopefully, it will help someone.
@PlayCreatively In this manual, they mention that custom classes cannot be serialized if they are generic (though they don’t mention UnityEngine.Object-derived classes). They made custom generic classes serializable in Unity 2020, and I hoped ScriptableObjects can be generic too now, but nope. In the end, Unity has to find a comfortable way for users to choose generic argument types when they create a generic ScriptableObject asset or add a generic MonoBehaviour to an object. Making custom classes serializable is easier because it doesn’t require UI changes.
How about using generic custom classes and serializing them with [SerializeReference]?
Should have the same effect as inheriting from ScriptableObject, no?
Edit: Hmmm it seems not - SerializeReference prevents object duplication upon deserialization but only at the class level - so multiple references to the same object in a given MonoBehaviour would be preserved, but if another MonoBehaviour referenced that object I believe it would end up with a different copy.