- Home /
Property draw a class that has a generic type
There isn't much to say... I just want to know if it's possible to property draw a class that has a generic type. If the answer is no just say no (I don't really need an alternative solution, so I don't need to add more detains. I have a different solution, but I don't like it), if it is so how am I suppose to do it?
edit(Moved from answer):
I will just specify what I want, because my other answer won't work:
I have a class called "Attack", which contains some properties an attack has (such as a name, or a cost), and a delegate, which is the method being called when attacking. The delegate is a delegate called "VoidFunc" (when I made it I didn't know about the Action delegate, and what I made is basically a Func delegate without a return type). The Attack class has a few overloads, each one adds one generic, and that generic is the generic type in the delegate. Here is an example for one with one generic type:
[System.Serializable]
public class Attack<T>
{
public string name;
public int cost;
public VoidFunc<T> attackMethod;
}
Now I need to make a custom property drawer for this. I have a non-generic overload, which worked perfectly fine, but it is not what I need. My initial attempt was this:
[CustomPropertyDrawer(typeof(Attack<T>))]
public class AttackPropertyDrawer<T> : PropertyDrawer
But apparently you can't use generic types in attributes (I would actually like to know the logic behind it)... So I tried instead of making the class generic and put the generic type in the Attack type, just use the object keyword, meaning I will do "Attack
Answer by Bunny83 · Jun 29, 2016 at 12:11 PM
Unity's serialization system doesn't support serializing generic types except the generic "List" type. The inspector can only edit things that are serializable by Unity.
edit
Since you have added more details i will get a more detailed answer.
Again, Unity doesn't support serializing generic types. Furthermore delegates can't be serialized by Unity in general. Unity now supports a special delegate wrapper type called "UnityEvent". This class is defined in the "UnityEngine.Events" namespace.
Unity also implemented a generic version of that class in order to specify event parameters. However as i said Unity doesn't support generic types, that's why you have to create a concrete type out of the generic type in order to be serializable.
[System.Serializable]
public class EventWithStringParam : UnityEvent<string> { }
You can use generic base classes but the final classes and types that are used have to be concrete, non-generic types if you want them to be serializable and to be viewable / editable in the inspector.
Make sure you read the UnityEvent documentation carefully, especially the last paragraph about the generic type.
So how are there some plugins that make the dictionary appear in the inspector? They probably used the PropertyDrawer.
A PropertyDrawer only alters the way how serialized properties are displayed. You can implement a custom editor / inspector for the containing class. A custom editor could display pretty much anything but editing is pretty pointless since the generic classes aren't serialized.
Your question is worded in a very abstract way so it's not clear what you actually want to achieve.
I actually didn't want the methods to appear, though it would be nice... But if I do it, I would like to only have one slot for one method, not a full UnityEvent. But that wasn't even the problem, what I wanted to do is to make them show up (and in a custom way) even without the method.
Once and for all: Unity does not support serializing generic types at all with the one and only special excpetion: List<T>
.
So if you use a generic parameter in your type definition, no matter if the type is actually used or not, it can't be serialized by Unity and thus can't be edited in the inspector. You have to get rid of your generic parameter if you want it to be visible in the inspector. That's it.There's no way around that.
ps. You again posted an comment as answer. I again converted the answer into a comment but that was the last time. I again advise you to read the user guide and the FAQs
For some reason I didn't get an Email saying I got an answer, so that's why it's so late...
Ok, I read the user guide. The reply I make now might not be good, and maybe it should have been an answer, but the user guide didn't contain anything against it, so let's just hope it will be fine...
I made something like this
public class AttackWithPlayer : Attack<Player> { }
And then when I made the property drawer, I did it like that:
[CustomPropertyDrawer(typeof(Attack))]
[CustomPropertyDrawer(typeof(AttackWithPlayer))]
public class AttackPropertyDrawer : PropertyDrawer
And the variable I made was like that:
public AttackWithPlayer testAttack;
You might say I give too much details in code, ins$$anonymous$$d of explaining in sentences, but this is the best way I can show it. I have no idea how, but it doesn't work... $$anonymous$$aybe like it doesn't edit that class even if it's not generic, only because it's base class is generic. How does it make sense? And is it suppose to be like that?
Answer by ModLunar · Jan 17, 2020 at 04:42 PM
Unity 2020. Still in alpha, but I'm never going back. It was just like this in 2018.3 with Nested Prefabs. WOO!
If you have this for example, as a data class:
using System;
using UnityEngine;
[Serializable]
public class Blah<T> {
[SerializeField] private T value;
}
Then you can use the following code snippet for your PropertyDrawer.
using UnityEditor;
using UnityEditor;
[CustomPropertyDrawer(typeof(Blah<>))]
public class BlahDrawer : PropertyDrawer {
//... (your typical PropertyDrawer stuff here).
}
Just note your PropertyDrawer should NOT be generic itself, but you can use typeof(Blah<>)
without any type in between the angle brackets, to specify any type can go there. This is confirmed to work in Unity 2020.1.0a18 as of today, and thank the heavens.
Answer by jdean300 · Jun 29, 2016 at 11:54 AM
It's possible with a bit of hacking. The generic class that you want to create a property drawer for needs to inherit from a non-generic base class, and then you can create a property drawer for the non-generic class.
public class NonGenericBase {}
public class GenericType<T> : NonGenericBase {}
[CustomPropertyDrawer(typeof(NonGenericBase ))]
public class NonGenericBaseDrawer {}
That only works with the variables of type NonGenericBase, but when I make a variable of type GenericType, it doesn't draw it. Do you have any other solution?
Yes, it's works for class, but you should indicate that the drawer also works for inherited childs: [CustomPropertyDrawer(typeof(NonGenericBase), true)]
Unfortunately, it doesn't works for struct, which couldn't be inherited... I am looking for a custom drawer adapted to System.Nullable
This method doesn't seem to be working in Unity 2019 unfortunately. Though apparently you can do this without workarounds in Unity 2020, but that's not quite fully released yet at this exact moment.
Your answer
Follow this Question
Related Questions
Extended class attributes/methods referenced as base class attributes/methods 1 Answer
Custom editor: Drawing generic properties 1 Answer
I need a dictionary for a custom inspector 0 Answers
Putting a UnityEvent PropertyDrawer into a Custom Editor Window 1 Answer
Cannot get a class to show up correctly in a custom inspector 0 Answers