通用类C#Unity的自定义属性抽屉

时间:2014-07-22 16:32:54

标签: c# generics properties unity3d drawer

我在检查器中显示Serializable泛型类时遇到问题。

Serializable泛型类如下:

using UnityEngine;
using System;
using System.Collections;

[Serializable]
public class GenericClass<T> where T : struct
{
    [SerializeField]
    string _serializedString;

    public string SerializedString
    {
        get { return _serializedString; }
        set { _serializedString = value; }
    }

    ... // Functions using the generic type
}

自定义属性抽屉如下:

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(GenericClass<>))]
public class GenericClassDrawer: PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        SerializedProperty stringProperty = property.FindPropertyRelative("SerializedString");

        stringProperty.stringValue = EditorGUI.TextField(position, stringProperty.stringValue);
    }
}

MonoBehaviour我正在使用测试通用类如下:

using UnityEngine;
using System.Collections;

public class TestClass : MonoBehaviour 
{
    enum BasicEnum
    {
        First,
        Second,
        Third,
        Fourth
    }

    [SerializeField]
    GenericClass<BasicEnum> _editorEnum;
}

使用此当前代码,MonoBehaviour TestClass不会在检查器中显示任何内容。它应该显示一个文本字段。

我认为这是由于该类的通用性质,但我一直无法找到使用带有通用类的自定义属性抽屉的任何人的示例。

我的问题是 - 这可能吗?我在代码中遗漏了哪些文本字段按预期显示?如果当前代码不可能,那么泛型类的属性抽屉是否有任何变通方法?

感谢您的时间!

3 个答案:

答案 0 :(得分:6)

这不会起作用,因为Unity当前(4.x / 5.0)不会序列化泛型类。序列化泛型的一个技巧是继承它们。例如,在这种情况下,您可以:

[Serializable]
class GenericClassInt: GenericClass<int> { ... }

[Serializable]
class GenericClassFloat: GenericClass<float> { ... }

然后你可以拥有字段的编辑器:

[CustomPropertyDrawer(typeof(GenericClassInt))]
[CustomPropertyDrawer(typeof(GenericClassFloat))]
public class GenericClassDrawer: PropertyDrawer { ... }

这不是那么优雅,但解决了这个问题。

答案 1 :(得分:0)

我不是绝对肯定的,但在我过去的经验中,Unity不支持Generic类的CustomPropertyDrawers。

答案 2 :(得分:0)

一种解决方法是从非泛型抽象基类继承。这是有效的,因为property.FindPropertyRelative(...)在运行时查找值而不是编译时间,因此它在具体的运行时实例中找到值。

[Serializable]
public abstract class Generic { }

[Serializable]
public abstract class Generic<T> : Generic {
    public T value;
}
[Serializable]
public class GenericInt : Generic<int> { }
[Serializable]
public class GenericFloat : Generic<float> { }

[CustomPropertyDrawer (typeof (Generic), true)]
public class IngredientDrawer : PropertyDrawer {
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
        EditorGUI.BeginProperty (position, label, property);
        position = EditorGUI.PrefixLabel (position, GUIUtility.GetControlID (FocusType.Passive), label);
        EditorGUI.PropertyField (position, property.FindPropertyRelative ("value"), GUIContent.none);
        EditorGUI.EndProperty ();
    }
}