Почему не сериализуются ссылки на объекты в 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 месяца, а ты как мышь из анекдота: плачет, колется, но продолжает упорно есть кактус.