Scripting: The serializer can now serialize fields of generic types (e.g. MyClass someField) directly; it is no longer necessary to derive a concrete subclass from a generic type in order to serialize it.
I’d argue this beauty needs its own entry in the 2020.1 features list!
[CustomPropertyDrawer(typeof(Container<>))]
public class ContainerPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property.FindPropertyRelative("Value"), new GUIContent(fieldInfo.FieldType.GetGenericArguments()[0].FullName));
}
}
[CustomPropertyDrawer(typeof(Container<string>))]
public class StringContainerPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property.FindPropertyRelative("Value"), new GUIContent("String!"));
}
}
This works. You can get the generic argument type with fieldInfo.FieldType.GetGenericArguments(). Plus it looks like it picks the more specific attribute if it exists.
Cool, thanks. That’ll be really, really useful. We have a SerializableDictionary implementation, and each of them requires both a concrete subclass and a concrete drawer subclass, so this will save us a ton of code.
using System;
using UnityEngine;
[Serializable]
public class A
{
public int a;
}
[Serializable]
public class B : A
{
public int b;
}
[Serializable]
public class C : A
{
public int c;
}
[Serializable]
public class D<T> : A
{
public T d;
}
public class TestSerializeReference : MonoBehaviour
{
[SerializeReference]
public A a = null;
public D<int> d = new D<int>();
public bool changeType = false;
private void OnValidate()
{
if (changeType)
{
if (a == null || a is D<int>)
{
a = new A();
}
else if (a is C)
{
a = new D<int>();
}
else if (a is B)
{
a = new C();
}
else
{
a = new B();
}
changeType = false;
}
}
}
I took a quick look at it recently and only got an editor crash when executing “a = new D();”. Hope it’s juste an alpha bug and that it will be supported in the future.
This looks nice, tested a few cases. This will probably enable Unity to also mark the UnityEvent classes as serializable and make them non abstract; so that we could serialize UnityEvent directly without creating a subclass first.
Yep, just found that too and reported it with a tiny repro. It crashes if any generic class is directly serialized with SerializeReference with compute_class_bitmap: Invalid type 13 for field Container`1[T]:Value
All editor crashes are bugs that should be reported. It might not be that the feature is supposed to be supported, but nothing should crash the editor.
Are list of generic classes supposed to show up in the inspector?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestSerialization : MonoBehaviour
{
[System.Serializable]
public class D<T>
{
public T d;
public T d2;
}
public List<D<int>> myclass = new List<D<int>>();// doesn't show up in the inspector'
public D<int> myclass2;
}
There’s an open bug about that right now. The main issue is fixed but we’re resolving one secondary issue about how it interacts with [SerializeReference].
Is there any plan to support generics for scriptable objects too?
Knowing enough about how they work and comments about UnityEngine.Object not being supported together with SerializeReference this is probably a no.
In the below example, genericMonoA showed in inspector as an Object field(as expect),
but genericMonoB was treated as a pure class with foldout in inspector, and will call new() on game start (prohibited for MonoBehaviour)
Is this some kind of bug?
using UnityEngine;
[System.Serializable]
public class GenericMono<T> : MonoBehaviour
{
[SerializeField]
T t;
}
public class GenericMonoFloat : GenericMono<float> { }
public class GenericBehaviour : MonoBehaviour
{
[SerializeField]
GenericMonoFloat genericMonoA;
[SerializeField]
GenericMono<float> genericMonoB;
}
Is there a way to serialise it manually and get the result? Similar to how JSONUtility works - it has the same constraints as the current serialisation used by Unity. Is there an equivalent for this new serialisation?
This feature doesn’t seem to work with arrays/lists of types that have a generic parameter. For example…
[CreateAssetMenu(menuName = "Tables/Weapon")]
public class WeaponTable : Table<Weapon>
{
}
public abstract class Table<TValue> : ScriptableObject
{
public Row<TValue>[] rows;
}
[Serializable]
public struct Row<TValue>
{
public TValue value;
public int rating;
}
It works if table has just one row but not an array of them.