C# 在inspector中显示不可变(只读)结构的只读字段
我有以下不可变结构C# 在inspector中显示不可变(只读)结构的只读字段,c#,unity3d,C#,Unity3d,我有以下不可变结构 [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
[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;
}
[可序列化]
公共只读结构风
{
///风速
///空气密度,如果未提供15度,则假定为1.225f
公共风(矢量3风速,浮标rho=1.225f)
{
速度=风速;
Rho=Rho;
}
///
///风速[m/s]
///
[显示只读]
公共只读矢量3速度;
///
///空气密度[kg/m^3]
///
[显示只读]
公共只读浮点Rho;
}
问题是Unity无法序列化只读字段,因此我遵循Anton Semchenko关于如何在inspector中将属性设置为仅显示这些字段的内容,以便于调试
以下是我制作的脚本:
自定义属性抽屉
[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));
}
}
[CustomPropertyDrawer(typeof(DisplayReadOnlyAttribute))]
公共类DisplayReadOnlyAttributeDrawer:PropertyDrawer
{
public override void OnGUI(Rect位置、SerializedProperty属性、GUIContent标签)
{
DisplayReadOnlyAttribute att=(DisplayReadOnlyAttribute)属性;
object obj=property.serializedObject.targetObject;
Type Type=obj.GetType();
FieldInfo field=type.GetField(property.propertyPath,BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
对象值=字段?.GetValue(obj);
if(att.warningIfNull&(val==null | | val.ToString().Equals(“null”))
val+=“因此,最后我使用了一个定制的inspector GUI,因为Unity由于限制无法将PropertyAttribute
s挂钩到只读字段
[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
}
[可序列化]
公共只读结构风
{
///风速
///空气密度,如果未提供15度,则假定为1.225f
公共风(矢量3风速,浮标rho=1.225f)
{
速度=风速;
Rho=Rho;
}
///
///风速[m/s]
///
公共只读矢量3速度;
///
///空气密度[kg/m^3]
///
公共只读浮点Rho;
#如果统一编辑器
[CustomPropertyDrawer(类型(风))]
公共类WindDrawer:PropertyDrawer
{
公共覆盖浮点GetPropertyHeight(SerializedProperty属性,GUIContent标签)
{
返回EditorGUIUtility.singleLineHeight*4+6;
}
public override void OnGUI(Rect位置、SerializedProperty属性、GUIContent标签)
{
//只读字段在构造时初始化,所以我们需要等待它们
bool readonlyInitialized=GameManager.LevelController;
//获取只读字段值
var rho=类型(风).GetField(名称(rho));
var speed=类型(风)。GetField(名称(速度));
var windRect=新矩形(位置x,位置y+18,位置宽度,16);
var rhorrect=新的Rect(位置.x,位置.y+42,位置.width,16);
var speedRect=新矩形(位置x,位置y+66,位置宽度16);
EditorGUI.BeginProperty(位置、标签、属性);
{
EditorGUI.LabelField(windRect,label);
EditorGUI.indentLevel++;
EditorGUI.BeginDisabledGroup(true);
{
EditorGUI.Vector3字段(rhoRect,名称(速度),
//无法定义只读字段时,默认值为Vector3.0
readonlyInitialized?(Vector3)speed.GetValue(GameManager.LevelController.WeatherController.Wind):Vector3.zero);
}
EditorGUI.EndDisabledGroup();
}
EditorGUI.EndProperty();
EditorGUI.BeginProperty(位置、标签、属性);
{
EditorGUI.BeginDisabledGroup(true);
{
EditorGUI.FloatField(speedRect,nameof(Rho),
//无法定义只读字段时,默认值为零
readonlyInitialized?(float)rho.GetValue(GameManager.LevelController.WeatherController.Wind):0.0f;
}
EditorGUI.EndDisabledGroup();
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
}
#恩迪夫
}
这将生成以下编辑器GUI:
瞧:编辑器窗口中显示了只读结构
我认为这不值得付出努力,如果你真的需要性能,那么就使用它,并在backingfield中附加一个readonly属性
[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; }
}
[可序列化]
公共结构风
{
///风速
///空气密度,如果未提供15度,则假定为1.225f
公共风(矢量3风速,浮标rho=1.225f)
{
速度=风速;
Rho=Rho;
}
///
///风速[m/s]
///
公共向量3速度{get;}
///
///空气密度[kg/m^3]
///
公共浮点数Rho{get;}
}
[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; }
}