由于我完全没有想法,我想我会在这里发布,以防有人知道为什么会这样。
我有一个名为 Behavior 的简单类,它保存一个字符串和一个字符串数组。它看起来像这样:
[System.Serializable]
public class Behaviour {
public string Methodname;
public string[] Parameters;
}
正如您可能已经预料到的,这个类是为了保存一个方法,以便可以将方法插入统一检查器。Methodname 是插入的方法的名称,而 Parameters 是以静态实用程序类可以读取的方式格式化的该方法的所有参数(这些字符串被转换为对象,然后用作参数。所以一个字符串“i25 " 将转换为 25 的整数参数。该数组是一个字符串,因为 object[] 无法序列化,因此无法保存。
我将剔除所有不必要的逻辑并专注于出了什么问题。让我们假设我们想要将一个整数保存到参数数组的第一个索引中。行为的 PropertyDrawer 将如下所示:
[CustomPropertyDrawer(typeof(Behaviour))]
public class BehaviourEditor : PropertyDrawer {
private Behaviour propertyReference;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
propertyReference = fieldInfo.GetValue(property.serializedObject.targetObject) as Behaviour;
// Check if the string array is null. This happens the very first time the scriptable object is created
if(propertyReference.Parameters == null) propertyReference.Parameters = new string[1];
// Check if the first index is null. In this simplified example also only happening the very first time.
if(propertyReference.Parameters[0] == null) propertyReference.Parameters[0] = "i0";
int value = (int)DataConverter.StringToObject(propertyReference.Parameters[index]);
value = EditorGUILayout.IntField(value);
propertyReference.Parameters[0] = DataConverter.ObjectToString(value);
}
}
DataConverter 简单地将对象转换为字符串,反之亦然(因此 int n = 9 将变为“i9”或“i255”将变为对象 x = 255)。所有这些逻辑都有效。
再次澄清:这是PropertyDrawer的Behavior。行为是ScriptableObject中的私有 [SerializedProperty] 。
如果数组为空,则 if == null 触发并将数组参数设置为长度为 1。后面的逻辑一切正常,我们可以从 EditorGUILayout 为 int 字段赋值,并且那里的值正确保存到数组中。所有这些逻辑都有效。
但是:有些东西正在改变行为的参数数组。我相信这个东西是ScriptableObject。下一帧,Parameters 不再为空(显然),我们尝试访问索引位置 0。这导致索引超出范围异常,因为某些内容将 Parameters 更改为新字符串 [0]。他们没有将其设置为 null,而是将其长度设置为 0。
为什么?什么可能触发这个逻辑?如果我将参数设置为属性并在设置方法中设置断点,除了上面我自己的代码之外没有其他人调用它,但数组的长度仍然为 0。有什么想法吗?
下面的答案是正确的:代码没有被正确应用,因此被序列化过程覆盖。必须添加 BeginProperty() 和 EndProperty()。
对于将来发现此问题的任何人,最终代码如下所示:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
SerializedProperty parameters = FindPropertyRelative("Parameters");
EditorGUI.BeginProperty(position, label, property);
// the enum popup for Methodname not shown here to keep it simple
if(parameters.arraySize == 0) parameters.arraySize = 1;
SerializedProperty element = parameters.GetArrayElementAtIndex(0);
if(element.stringValue == string.Empty) element.stringValue = DataConverter.GetObjectDefaultString(typeof(int));
int temp = (int)DataConverter.StringToObject(element.stringValue);
temp = EditorGUILayout.IntField(temp);
element.stringValue = DataConverter.ObjectToString(temp);
EditorGUI.EndProperty();