Select SubClass Type in Inspector for Field of BaseClass Type

Why is there no upfront support for this? It seems like it would be EXTREMELY empowering.

What I want is to select from the inspector which subclass to use on a field which has its baseclass as type, then work with the fields contained within that subclass. This would NOT require an instance of the class to already exist but would perhaps require a process of creating and storing an instance behind the scenes so to speak?

Currently, I can only work with a Class type field by using a Monbehaviour which exists in the scene, which in no way achieves what I want here, or a ScriptableObject instance for which I would need to create a new instance for each assignment for the contained fields to be what I need and that would mean clutter…

So far my research has resulted in people stating that unity simply does not support this kind of behavior, but why not? We have MonoBehaviour, we have ScriptableObject, so why can’t we have something like “SelectableType” to derive from which would allow us to utilize State Pattern from the inspector? Seems way too powerful a tool to shrug off…


At any rate, any suggestions on how to achieve this kind of thing? I need to be able to, when assigning to a field of a class type which derives from a “SelectableType” class, have the option to assign any of its subclasses as the type and then assign the fields of the chosen subclass.

What you are looking for is SerializeReference. Unfortunately you will need to at least write a custom inspector for choosing the class or copy any of the ones floating around the forum.

How would I go about the custom inspector? I’ve never done that…

If you’ve never written one your best bet is to look through the asset store/online for free options. Otherwise paid options like Odin Inspector exist that support SerializeReference out of the box.

I wouldn’t mind trying to write one if I could get a general breakdown of how to go about it. Maybe a decent guide you know of?

So far I have tried to get one going using chatGPT but it has lead me down several dead ends…

Lots of results in google like the Medium entry on the topic: SerializeReference in Unity. Hands-on new [SerializeReference]… | by Aleksander Trępała | Medium

Or this implementation on Github: GitHub - elmortem/serializereferenceeditor: Unity SerializeReference Editor There are several more.

1 Like

If you’ve never written a custom inspector you have a looot of learning to do (perhaps years) for something like a subclass selector which is straight in advanced territory.

I’d use an existing solution, or, take a look at how they do things code wise.

Start with Unity’s manual for how to make a custom Inspector in general.

Once you’ve got one, look up C# how-tos for getting a list of sub-classes of a target in the current domain, and then for creating an instance.

You’ll also need to make sure it’s serializable by Unity, also covered in the manual.

It’s a bit complex, but take it one step at a time and you’ll get there. Of course, if anything I’ve daid doesn’t make sense yet then there are some extra steps. :slight_smile:

Thankfully we have UnityEditor.TypeCache to make that a lot quicker these days.

Otherwise dealing with managed references is going to be a fun learning experience.

wow y’all are awesome! thanks to the direction given so far, i have almost what i need. followed the medium guide, made a few adjustments, applied TypeCache code to make it cleaner, and it works pretty well. this is what i have so far:

public class TestBehaviour : MonoBehaviour
{
    [SerializeReference] public SelectableType selectableType;
}

public class SelectableType
{
    [SerializeField] private bool testing;
    public int TestInt
    {
        get; set;
    }
}
[CustomEditor(typeof(TestBehaviour))]
public class SelectableTypeEditor : Editor
{
    private Type[] selectableTypes;
    private int selectableTypeIndex;
    private bool lockSelectableType = true;
    public override void OnInspectorGUI()
    {
        TestBehaviour testBehaviour = target as TestBehaviour;
        if (testBehaviour == null)
        {
            return;
        }
        if (selectableTypes == null)
        {
            selectableTypes = TypeCache.GetTypesDerivedFrom<SelectableType>().Where(p => typeof(SelectableType).IsAssignableFrom(p) && !p.IsAbstract).ToArray().Where(impl => !impl.IsSubclassOf(typeof(UnityEngine.Object))).ToArray();
        }
        selectableTypeIndex = EditorGUILayout.Popup(new GUIContent("SelectableType"), selectableTypeIndex, selectableTypes.Select(impl => impl.FullName).ToArray());
        if ((lockSelectableType = GUILayout.Toggle(lockSelectableType, "LockSelectableType")) == false
            && GUILayout.Button("Create instance"))
        {
            testBehaviour.selectableType = (SelectableType)Activator.CreateInstance(selectableTypes[selectableTypeIndex]);
            lockSelectableType = true;
        }
        base.OnInspectorGUI();
    }
}

//---

public class TestA : SelectableType
{
    [SerializeField] private int testInt;
    [SerializeField] private bool tester;
}
public class TestB : TestA
{
    [SerializeField] private int testInt2;
}

Now where i need to go from here:
I need, hopefully there is a way, to get around the requirement of writing this custom editor typeOf attribute to refer to each class i want to implement its functionality. I’m hoping there’s a way to apply the functionality directly to the SelectableType class i created, so that whenever i have a field of type SelectableType or any of its subclasses, the editor automatically apply the [SerializedReference] attribute to that field and will apply the result of our code so far. i think i am suppoosed to use…PropertyDrawer? research and chatGPT suggest that’s the route to take next, but i’m not sure i understand how.

I hope that makes sense, and any further help would be most appreciated, as its difficult to find a correct answer by searching when i dont know exactly what to search for as far as terminology xD

thanks again!

1 Like

The Editor can’t know to serlialize a field from its type alone, which is why [SerializeField] exists. It’s perfectly normal to mark a field as “[SerializeField] private float whatever = 2.0f;” when working in Unity, so you’re going to be doing that a lot anyway (or using ‘public’ if you’re that way inclined).

But yes, once the Editor knows it has to serialize something, if there’s a matching PropertyDrawer it will be used to present it in the Inspector, so you shouldn’t have to repeat the presentation code.

In short:

  • Unity knows what to serialize based on compatible fields being marked with [SerializeField] and/or being public.
  • The Inspector draws fields based on Component-specific code, PropertyDrawers, or using Inspector defaults.

Hi I’m trying to do the exact same thing.
Did you by any chance make progess on the topic? I know its been a year but maybe you’ll be able to save me a lot of time :slight_smile:

Anyway thanks to all of you! Now I know that what I want to do is not impossible and I might find a solution eventually.