Generics in Unity editor

Hi I have a class A, B and C

B and C inherits from A. In a script I have a public List which can be seen and edited in the Unity editor. However it is not possible for me to determinate if the exposed list should hold elements of B or of C since they both are of type A.

How would this be possible to do? I can imagine some editor scripting. But I am still new to this.

If you’re using the list to hold both types of C and B, you can check what you get from the list by attempting to cast the result A you get from the list to the type of B and C, if it casts correctly, you have your reference, if it’s null you know to try another cast type.

But how to do it in the editor?

I’m not really sure what you mean, if the list should only contain one or the other, make sure the list is only of that type.

If you absolutely have to have the list able to take both types, but is only meant for one type, you can have an editor script that will pop up and test the first element in the array for it’s type, and tell you the answer, but this seems like more of an issue of self-management. If I’m understanding your question correctly, it sounds like you need to re-design your code structure.

What im trying to achieve is to be able to switch in the editor whether the list should take in B or C objects and hence expose the fields of either the B or C class in the editor List. I forgot to mention that the classes have the [System.Serializable] tag. I thought about something like a drop down menu saying I want either B or C…

Right ok, I understand you now.

This is definitely possible, you’ll need to do a custom editor script as you’d guessed. Unity has a good guide for this:

Layout options:

Tutorial/Guide:

My guess is that you’ll need a toggle/checkbox to determine whether you expose the list for B or C.

Ok thanks I will take a look, but im also thinking about how to make the switch once I have the editor script.

For instance it is not possible to do something like this:

List<A> list = new List<B>();

It gives a cast error.

You’ll have to iterate through your array once the application starts and cast each member to a type of A, then assign to the final list of type A.

You can’t do that; List needs to be List, so keep it that way. If you need to add B or C to it then, assuming B and C derive from A, you can do : list.Add(instanceOfTypeA) or list.Add(instanceOfTypeB)

You also can use the Cast method and ToList method:

You need to add the namespace System.Linq to use this.

var ListOfB = new List<B>();
...
ListOfB.Cast<A>().ToList();

You haven’t made your case plain enough for us to understand so it’s hard to help you here, but my guess is that you don’t want to use inheritence at all, and that you should look into interfaces for what you want to achieve. Give us a clear idea of what you’re trying to accomplish, it will help us help you.

Ya, but I get a feeling his whole approach using inheritence is not what he needs and having to perform these casts are a symptom of this.

The reason im using inheritance is so that I can make the system more flexible. I have a list of the Events which hold another list of type Dialog. Dialog is the A class and it can have several classes which inherit from it.

	[System.Serializable]
	public class Events
	{
		public List<Dialog> dialogClips;	
	
	}

public List<Events> events;

What I want to achieve is using this structure for whatever kind of Dialog I have. So the events list should be run through without caring for whatever is inside from the code point of view.

The reason for the whole editor thing is so that you easily can place in the parameters and clips for each Dialog type. Regardless of what type it is. But each type will of course have its own fields exposed.

Hope this makes things more clear.

Ok, let’s see if I have this right… Your Events class contains a list of Dialogs and each Dialog in this list can be (for simplicity sake) DialogA or DialogB, and when the list shows up in the editor inspector window, you want each Dialog in the list to expose those particular properties corresponding that that particular Dialog type. Is this correct? So let’s say you have a list containing DialogA and DialogB, and DialogA has a string property and DialogB has an int property, you want to be able to see a list with 2 items, one containing a string property that can be set, and the other with an int property that can be set?

Oh I’m sorry… are these actual Dialog windows? In that case, you want two windows, one with a string and the other with an int?

If so, then you’ll need to create either

  1. a custom editor that uses reflection/attributes to automagically display the properties you want exposed and pass it the dialog instance

or

  1. a custom editor for each Dialog type that exposes whatever you want, and you’ll know what type of Dialog to show based on the following check : if (dialogClip is DialogA) { // create DialogA window here } else if (dialogClip is DialogB) { // create DialogB window here }

There is no way around writing your own GUI inspector/editor.

When you down-cast a object (i.e. AudioEvent to Event), then only the Event properties are exposed, because you reduce it to the least common denominator. In order to access the “extended” features you have to upcast it.

However, there is an issue with that: When you got a List list, you can not add a B or C object to it via inspector (by default), unless you have a button (or pulldown list + add) button in the inspector, as Unity will by default add an A when extending the list.

So actually such a list shouldn’t be exposed in the Editor anyway.

It may be better to create an Editor, with a button “Edit events”, which opens an EditorWindow in which you have a list of all events (on the left) and it’s types and when you click on one if it, in the right side of the window displays the properties.

I only want the events to be able to hold either B or C never mixed. The classes Event and Dialog are all custom classes I made which are made serializable. I dont have any way to check what is actually put into the list as everything will be put in through in the inspector. Hence I need to be able to tell what I want to put in before I actually add the values to their exposed fields.

Im still new to editor scripts, so any pointers in the right direction are highly appreciated.

You can’t do that. When you declare it as List it’s possible to add A, B and C (unless A is abstract, then only B and C).

That being said, it prevents you from editing members of B and C, which kind of beats the purpose of having it visible in the Inspector, as it makes no sense to make millions of prefabs to assign it via inspector. The best way for you would be simply to declare it either List or List as this is the only way to assure only B or only C is in it.

MADMarine already posted two links. Basically you extend EditorWindow class

import UnityEditor; 
public class MyEventEditorWindow : EditorWindow {

    void OnGUI() {
        // Do your GUI code here. Basically it's the same as OnGUI in your MonoBehaviour scripts, you just use stuff from EditorGUI instead of GUI
        // http://unity3d.com/support/documentation/ScriptReference/EditorGUI.html
    }
}

// This will replace the MyClassNameThatContainsTheEvents class Inspector with your own one
[CustomEditor(typeof(MyClassNameThatContainsTheEvents))]
public class MyClassNameThatContainsTheEventsEditor {

    void OnInspectorGUI() {
        // draw the normal inspector 
        DrawDefaultInspector();
        if(EditorGUILayout.Button("Events Editor")) {
            EditorWindow.GetWindow(typeof(MyEventsEditorWindow));
        }
    }
}

public class MyClassNameThatContainsTheEvents : MonoBehaviour {
    public int someValue;
    public int someString;
    [HideInInspector]
    public List<A> events = new List<A>();
}

Then a new window should get opened, where you can design your event editor UI with all kind of checks you want

The HideInInspector will make sure the list is not displayed in the inspector, but will still be serialized. This prevents accidental editing in the inspector view and makes the Editor window the only way to edit the events.

Just a basic construct to give you an idea. untested.