How Can I Create A PropertyDrawer For My Custom Generic Class?

Hey I have been trying for a while now but cant seem to get Unity to recognize my generic class in the inspector. Can someone please give me an example on how this would be done in this case below? :

The Class:

[System.Serializable]
public class TableItem<TKey, TValue> {
	public TKey Key = default(TKey);
	public TValue Value = default (TValue);
	public TableItem(TKey Key, TValue Value){
		this.Key = Key;
		this.Value = Value;
	}
}

What I Have For A Property Drawer So Far (I’m arbitrarily using <string, string> until I can get it working) :

[CustomPropertyDrawer(typeof(TableItem<string, string>))]
public class tableItemPropertyDrawing :PropertyDrawer {
	public void OnGUI(Rect pos, SerializedProperty prop, GUIContent label){
		Debug.Log (true);
	}
}

Thank You!

You cannot serialize a generic class. You CAN serialize a type derived from a generic class.

So instead of TableItem<string, string>, you can try:

// this derived type should serialize.
// the actual name of the class can be whatever you want
[System.Serializable]
public class StringTableItem : TableItem<string, string> { }
// we don't need an implementation, it's just to "wrap" our generic type
// in a concrete type that unity can serialize.
// the CustomPropertyDrawer should also use the concrete type too, I believe

It’s mildly annoying, but the reasons for it have to do with how the low-level unity serailizer works (and serializing generics is a complex problem on it’s own).

You can take a look at how to make your own UnityEvent<> types to see how this works in practice.

Hope that helps.

1 Like

That seems doable, heck my namespace script is already 1400 lines and counting so whats a few more lol

thanks!

Any Suggestions On Tutorials For The Unity Event <>Thing? Theres A lot of Non Helpful Info out There :stuck_out_tongue:

Here’s the Learn tutorial.

Here’s an example based on some of the ways I’ve used them (outside of UI callbacks, where the usage is obvious):

// A basic UnityEvent will serialize automatically, as it lacks any generic parameters.
// You can still wrap it in an empty sub-class to give it special meaning or make it's use clearer:
[System.Serializable]
public class LoadingFinished : UnityEvent { }

// Generic Unity events can be wrapped as in the example I gave earlier:
[System.Serializable]
public class StuffLoadedWithTotalTime : UnityEvent<UnityEngine.Object[],float> { }

// here's how you would use them:
public class Loader : MonoBehaviour
{
   // public serialization, less encapsulated:
   public LoadingFinished OnLoadingFinished = new LoadingFinished();

   // non-public serialization, more encapsulated:
   [SerializeField]
   private StuffLoadedWithTotalTime m_onStuffLoaded = new StuffLoadedWithTotalTime();
   public StuffLoadedWithTotalTime OnStuffLoaded
   {
        get { return m_onStuffLoaded; }
   }
   /* you could wrap the proceeding example with add/remove property handlers
    * for the listener AddListener/RemoveListener functions, and make it look
    * just like a normal C# event delegate to outside classes.
    */

     public IEnumerator Load(params UnityEngine.Object _stuff[])
     {
        var start_time = Time.realtimeSinceStartup;
        // loading stuff...

        var total_time = Time.realtimeSinceStartup - start_time;
        m_onStuffLoaded.Invoke(_stuff, total_time); // for the things that care what was loaded and how long
        OnLoadingFinished.Invoke(); // for the things that don't
     }
}

This makes it easy to get your own editor-exposed callback framework for custom systems.

I know this post is 6 years old, but for creating a property drawer for a generic type you would define

[CustomPropertyDrawer(typeof(TableItem<,>))]
public class TableItemPropertyDrawer : PropertyDrawer {
 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
  Debug.Log(true);
 }
}