【问题标题】:Display readonly fields of an immutable(readonly) struct inside the inspector在检查器中显示不可变(只读)结构的只读字段
【发布时间】:2020-06-30 17:32:47
【问题描述】:

我有以下不可变结构。

[Serializable]
public readonly struct Wind
{
    /// <param name="windSpeed">The speed of the wind</param>
    /// <param name="rho">The density of the air, if not provided 15 degrees assumed aka 1.225f</param>
    public Wind(Vector3 windSpeed, float rho = 1.225f)
    {
        Speed = windSpeed;
        Rho = rho;
    }

    /// <summary>
    /// The speed of the wind [m/s]
    /// </summary>
    [DisplayReadOnly]
    public readonly Vector3 Speed;

    /// <summary>
    /// Density of the air [kg/m^3]
    /// </summary>
    [DisplayReadOnly]
    public readonly float Rho;
}

问题在于,Unity 无法序列化只读字段,因此我按照 Anton Semchenko 的 guide 介绍了如何在检查器中仅显示这些字段以方便调试.

这些是我制作的脚本:

自定义属性抽屉

[CustomPropertyDrawer(typeof(DisplayReadOnlyAttribute))]
public class DisplayReadOnlyAttributeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        DisplayReadOnlyAttribute att = (DisplayReadOnlyAttribute)attribute;
        object obj = property.serializedObject.targetObject;
        Type type = obj.GetType();
        FieldInfo field = type.GetField(property.propertyPath, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
        object val = field?.GetValue(obj);

        if (att.warningIfNull && (val == null || val.ToString().Equals("null")))
            val += " <-This value should NOT be NULL!";

        EditorGUI.LabelField(position, string.Format("{0}: {1}", label.text, val));
    }
}

指示是否应在检查器中显示只读属性的属性

public class DisplayReadOnlyAttribute : PropertyAttribute
{
    /// <summary>
    /// Writes a warning if the value of this field is null
    /// </summary>
    public readonly bool warningIfNull = false;

    public DisplayReadOnlyAttribute(bool _warningIfNull = false)
    {
        warningIfNull = _warningIfNull;
    }
}

问题是,如果在只读字段上使用此属性将不起作用,它仅在用于非只读字段时才被调用public float Rho; 如果您知道如何以另一种方式显示只读字段,我不仅对上述解决方案感兴趣,请不要自己保留

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    所以最后我选择了自定义检查器 GUI,因为 Unity 由于限制而无法将 PropertyAttributes 挂钩到只读字段。

    [Serializable]
    public readonly struct Wind
    {
        /// <param name="windSpeed">The speed of the wind</param>
        /// <param name="rho">The density of the air, if not provided 15 degrees assumed aka 1.225f</param>
        public Wind(Vector3 windSpeed, float rho = 1.225f)
        {
            Speed = windSpeed;
            Rho = rho;
        }
    
        /// <summary>
        /// The speed of the wind [m/s]
        /// </summary>
        public readonly Vector3 Speed;
    
        /// <summary>
        /// Density of the air [kg/m^3]
        /// </summary>
        public readonly float Rho;
    
    #if UNITY_EDITOR
        [CustomPropertyDrawer(typeof(Wind))]
        public class WindDrawer : PropertyDrawer
        {
            public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
            {
                return EditorGUIUtility.singleLineHeight * 4 + 6;
            }
    
            public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
            {
                // Readonly fields are initialized at construction time so we need to wait for them
                bool readonlyInitialized = GameManager.LevelController;
                // Getting the readonly fields values
                var rho = typeof(Wind).GetField(nameof(Rho));
                var speed = typeof(Wind).GetField(nameof(Speed));
    
                var windRect = new Rect(position.x, position.y + 18, position.width, 16);
                var rhoRect = new Rect(position.x, position.y + 42, position.width, 16);
                var speedRect = new Rect(position.x, position.y + 66, position.width, 16);
    
                EditorGUI.BeginProperty(position, label, property);
                {
                    EditorGUI.LabelField(windRect, label);
                    EditorGUI.indentLevel++;
    
                    EditorGUI.BeginDisabledGroup(true);
                    {
                        EditorGUI.Vector3Field(rhoRect, nameof(Speed),
                        // Default value is Vector3.zero when the readonly field cannot be defined
                            readonlyInitialized ? (Vector3)speed.GetValue(GameManager.LevelController.WeatherController.Wind) : Vector3.zero);
                    }
                    EditorGUI.EndDisabledGroup();
                }
                EditorGUI.EndProperty();
    
                EditorGUI.BeginProperty(position, label, property);
                {
                    EditorGUI.BeginDisabledGroup(true);
                    {
                        EditorGUI.FloatField(speedRect, nameof(Rho),
                           // Default value is zero when the readonly field cannot be defined
                           readonlyInitialized ? (float)rho.GetValue(GameManager.LevelController.WeatherController.Wind) : 0.0f);
                    }
                    EditorGUI.EndDisabledGroup();
                }
                EditorGUI.indentLevel--;
                EditorGUI.EndProperty();
            }
        }
    #endif
    }
    

    这将产生以下编辑器 GUI:

    瞧:您在编辑器窗口中显示了只读结构

    如果你真的需要性能,我认为这不值得付出努力,否则只需使用它,并将只读属性附加到支持字段

    [Serializable]
    public struct Wind
    {
        /// <param name="windSpeed">The speed of the wind</param>
        /// <param name="rho">The density of the air, if not provided 15 degrees assumed aka 1.225f</param>
        public Wind(Vector3 windSpeed, float rho = 1.225f)
        {
            Speed = windSpeed;
            Rho = rho;
        }
    
        /// <summary>
        /// The speed of the wind [m/s]
        /// </summary>
        public Vector3 Speed { get; }
    
        /// <summary>
        /// Density of the air [kg/m^3]
        /// </summary>
        public float Rho { get; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2013-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多