Similar like SerializeReference
but works on generic property.
public interface IMyInterface<T> {}
public class MyIntObject : IMyInterface<int> {}
public class MyGenericObject<T> : IMyInterface<T> {}
public class MyMonoBehavior : MonoBehaviour
{
[GenericSerializeReference]
public IMyInterface<int> Value { get; set; }
}
Unity3D 2020.2 (not guaranteed to work below 2020.2)
OpenUPM: openupm add com.quabug.generic-serialize-reference
- Not support
struct
type. - Not support generic field.
- Not support variance.
- Extra time to generate IL code while building assembly
- Extra memory space to store a generated field for each property.
Either generate derived classes into a custom assembly named GenericSerializeReference.OverrideAssemblyCSharp or AssemblyCSharp.dll if there's no such custom assembly.
// Generate derived types into AssemblyCSharp.dll
public class MyMonoBehavior : MonoBehaviour
{
// [GenericSerializeReference(mode: GenerateMode.AssemblyCSharp)]
// public IMyInterface<int> Value { get; set; }
// 1. create a field named _Value with `IBase` type
// which should be able to serialized by `SerializeReference` attribute
[SerializeReference, GenericSerializeReferenceGeneratedField]
private GenericSerializeReference.IBase _Value;
// 2. inject code into property's getter and setter
// make sure property get value from serialized field first
// and setter set serialized field into null to avoid get from it next time.
[GenericSerializeReference]
public IMyInterface<int> Value
{
get
{
return (IMyInterface<int>) _Value ?? <Value>k__backingField;
}
set
{
<Value>k__backingField = value;
_Value = null;
}
}
}
// GenericSerializeReference.OverrideAssemblyCSharp or AssemblyCSharp.dll
// 3. gather derived types of property (`IMyInterface<int>`)
// then generate a non-generic version of those types and make them all implement `IBase` interface
namespace <GenericSerializeReference>
{
static class IMyInterface`1<System_Int32>
{
class MyIntObject : global::MyIntObject, GenericSerializeReference.IBase {}
}
}
Embed generated derived classes beside the property with GenericSerializeReferenceAttribute
.
// Embed into current class
public class MyMonoBehavior : MonoBehaviour
{
// [GenericSerializeReference(mode: GenerateMode.Embed)]
// public IMyInterface<int> Value { get; set; }
// 1. create a field named _Value with `IBase` type
// which should be able to serialized by `SerializeReference` attribute
[SerializeReference, GenericSerializeReferenceGeneratedField]
private <Value>__generic_serialize_reference.IBase _Value;
// 2. inject code into property's getter and setter
// make sure property get value from serialized field first
// and setter set serialized field into null to avoid get from it next time.
[GenericSerializeReference]
public IMyInterface<int> Value
{
get
{
return (IMyInterface<int>) _Value ?? <Value>k__backingField;
}
set
{
<Value>k__backingField = value;
_Value = null;
}
}
// 3. gather derived types of property (`IMyInterface<int>`)
// then generate a non-generic version of those types and make them all implement `IBase` interface
private static class <Value>__generic_serialize_reference
{
public interface IBase {}
public class MyIntObject : global::MyIntObject, IBase {}
}
}
- AssemblyCSharp mode: generate any type from AutoReferenced assemblies.
- AssemblyCSharp mode with custom GenericSerializeReference.OverrideAssemblyCSharp assembly: able to control which type should be generated by choosing certain referenced assemblies.
- Embed mode: generate any type from assemblies referenced by processed assembly.
Drawer modified from TextusGames's UnitySerializedReferenceUI with MIT license