Почему не сериализуются ссылки на объекты в SerializedProperty.boxedValue?
Продолжаю работу над окнами диалогов CustomEditorWindow. Диалоги содержат все необходимые публичные поля, далее в OnGui само окно сериализуется в SerializedObject, который выводится при помощи PropertyDrawer и EditorGuiLayout в окошке. Вот как-то так:
public void OnGUI()
{
so = new SerializedObject(this);
GUILayout.BeginVertical();
{
so.Update();
EditorGUILayout.LabelField(EditorWindow.focusedWindow.ToString());
EditorGUILayout.LabelField("Данные для сравнения");
EditorGUILayout.PropertyField(so.FindProperty("arg1"));
if (!string.IsNullOrEmpty(arg1?.ToString()) && compareType == SearchCondition.CompareType.None)
compareType = arg1.notVal ? SearchCondition.CompareType.NotExist : SearchCondition.CompareType.Exist;
EditorGUILayout.PropertyField(so.FindProperty("compareType"), GUIContent.none);
var argProp = so.FindProperty("arg2");
if (argProp != null)
EditorGUILayout.PropertyField(argProp);
so?.ApplyModifiedProperties();
EditorGUILayout.BeginHorizontal();
{
if (GUILayout.Button("Установить"))
SetValue();
if (GUILayout.Button("Отмена"))
this.Close();
}
EditorGUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
Возникла потребность при формировании диалога инициировать его ссылкой на компонент. Для этого добавил атрибут в котором передается название поля или метода откуда следует извлекать ссылку.
Объекты arg1 и arg2, это простой класс в основном состоящий из value значений. Но для того чтобы их настроить написан свой PropertyDrawer, который открывает диалог, а диалог должен быть инициирован ссылкой на компонент в качестве входящего параметра. Эта ссылка устанавливается в arg вручную до отрисовки, а arg по задумке должен ее извлекать перед созданием диалога и в редакторе создав диалог инициировать его.
С какой проблемой столкнулся. Если ссылка хранится в serializedObject, то мы спокойно ее получаем через parentProperty.serializedObject.targetObject. Но беда в том, что когда PropertyDrawer для arg1 пытается получить внутри себя ссылку из своего свойства Result, то на выходе получается null.
По факту получается в что в Window лежит ArgData, а внутри ArgData есть публичное свойство Result. В отладчике я вижу в SerializedObject.targetObject.arg1.Result, что это свойство заполнено. Но если я получаю serializedProperty для arg1 и пытаюсь через Reflection извлечь ArgData из boxedValue, то вижу в дебагере что все поля со ссылками null, а значимые заданы. При этом у сериализованного свойства arg1 ссылка SerializedObject.targetObject ссылается на окно и если дальше от него спускаться и проверить то Result содержит требуемую ссылку.
Пока вижу только один вариант. Парсить путь для serializedProperty.propertyPath и от SerializedObject.targetObject через Reflection получать значение на всю глубину serializedProperty.depth. Будут заморочки со списками поскольку propertyPath в формате Unity (типа такого args.Array.data[1].pathVal), но вроде все решаемо.
Может я как всегда все усложняю и есть более простой и правильный способ?
Ответы (1 шт):
Как я уже писал ранее, если ты создаёшь SerializedObject сам, это значит, что ты делаешь какую то херню и приводит это к какой-то херне. В документации даже не описан его конструктора, как бы намекая что для тебя, его НЕ СУЩЕСТВУЕТ! Ты лезешь в работу редактора, творя дичь и удивляешься, что от твоего SerializedObject, получаются пустые SerializedProperty.
Диалоговое окно это окошко с текстом и кнопками да/нет, никаких ссылок он не принимает. Что ты называешь диалогом, одному тебе известно.
Что мы должны увидеть в этом OnGUI? Груду лейаутов и монструозный if? А this это ваще чё? Это некий ArgData... а он чьи будет, от кого наследуется?
Почему в вертикали ты используешь GUILayout а в горизонтали EditorGUILayout? Грязь! IMGUI без пяти минут legacy и нужно переходить на Toolkit!
Существует один единственный способ отрисовки UnityEngine.Object и это Editor, который наследуется от ScriptableObject. Об этом чёрным по английски написано в документации, в первом же предложении:
Derive from this base class to CREATE a custom INSPECTOR OR EDITOR FOR your custom OBJECT.
Всё что требуется, это передать этот объект как target. То есть не нужно создавать никаких ScriptableObject и SerializedObject и заниматься самодеятельностью, все инструменты уже есть и процедуры написаны, какими они должны быть, без ошибок.
А PropertyDrawer используется для остальных сериализуемых типов, например struct. Такого объекта как ScriptableObject там существовать не должно ВООБЩЕ!, от слова "СОВСЕМ", ни в каком виде, на расстоянии пушечного выстрела, что можно заметить по документации. Он работает только SerializedProperty, полученным через аргумент в OnGUI или CreatePropertyGUI и всё.
Пытаешься из arg1 получить ArgData, который является обладателем поля arg1? Проворачиваем фарш обратно? Не понимая что творишь полную херню? Что бы что? Почему нельзя просто передать ArgData целиком? как target в новый Editor?
Может я как всегда все усложняю и есть более простой и правильный способ?
ДА! Максимально ужасным образом!
Лень всему голова, но в итоге потратишь больше времени и нервов пожиная последствия. Прошло почти 2 месяца, а ты как мышь из анекдота: плачет, колется, но продолжает упорно есть кактус.