Чем заменить метод OnEnable()?

Общие вопросы о Unity3D

Чем заменить метод OnEnable()?

Сообщение iprogrammer 21 июн 2018, 12:36

Делаю я инструмент непосредственно для Юнити. И у меня есть много классов, у которых есть свойство RectOffset. Это обычные классы, не наследуемы от ScriptableObject или Monobehaviour.
Я сериализую их и десериализую. И когда я их десериализую, я создаю экземпляры динамически с помощью Activator.CreateInstance(Type, Object[]);, пример:

Синтаксис:
Используется csharp
    public void OnAfterDeserialize() {
        Vector2 dropPosition = new Vector2(10, 10);
        Control child = (Control)Activator.CreateInstance(typeof(Button), dropPosition);
        child.Name = child.InitName;
        TestRectOffset =  new RectOffset(0, 0, 0, 0);
    }
 


Но, к сожалению, в этом случае Юнити выдает мне ошибку, что для заполнения значения RectOffset нужно использовать метод OnEnable():

> set_left is not allowed to be called during serialization, call it
> from OnEnable instead.
> See "Script Serialization" page in the Unity Manual for further details. UnityEngine.RectOffset:.ctor(Int32, Int32, Int32, Int32)



Конечно же у меня нет такого метода, ибо не наследуются от соответствующих классов и архитектурно не планирую. В будущем я планирую добавить еще много свойств, которые наверняка будут тоже могут выдавать такую же ошибку.

Что мне нужно сделать, чтобы сэмулировать метод OnEnable? Как можно корректно инстанциировать объект с помощью Activator.CreateInstance без этих ошибок?

-----------------------------------------
P.S. Я использую Unity 5.6.0p4
iprogrammer
UNец
 
Сообщения: 41
Зарегистрирован: 25 июн 2016, 07:10

Re: Чем заменить метод OnEnable()?

Сообщение ilkalawson 21 июн 2018, 13:21

Скорей сама логика у вас не правильная раз возникают противоречия, ну и еще не совсем понятно для чего вам нужно в десериализации создавать скриптовые объекты.

Как можно корректно инстанциировать объект

Скриптовые объекты можно еще создавать через new
ilkalawson
UNIверсал
 
Сообщения: 412
Зарегистрирован: 19 янв 2015, 20:38
Skype: lawsonunity

Re: Чем заменить метод OnEnable()?

Сообщение seaman 21 июн 2018, 15:44

На какую строку то ругается?
Не на эту?
TestRectOffset = new RectOffset(0, 0, 0, 0);
Сделайте ее в другом месте...
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: Чем заменить метод OnEnable()?

Сообщение iprogrammer 21 июн 2018, 16:42

seaman писал(а):На какую строку то ругается?
Не на эту?
TestRectOffset = new RectOffset(0, 0, 0, 0);
Сделайте ее в другом месте...

В каком?)) Мне это нужно делать при создании объекта. Может быть вы подскажите где писать?))

ilkalawson писал(а):Скорей сама логика у вас не правильная раз возникают противоречия, ну и еще не совсем понятно для чего вам нужно в десериализации создавать скриптовые объекты.

Как можно корректно инстанциировать объект

Скриптовые объекты можно еще создавать через new

Через new не делаю потому, что пример упрощенный и на самом деле считываются полные имена типов из строкого представления и подставляется Type, а не влоб пишется typeof(Button)

Вообще я делаю десериализацию кастомного класса, а точнее классов с рекурсивной вложенностью, как в примере из документации https://docs.unity3d.com/Manual/script-Serialization-Custom.html. Там при десериализации данные из заготовленного класса SerializableNode попадают в экземпляр класса Node , который, как вы выразились, создаются скриптовые объекты. Вот только там просто Node, а у меня много наследников, поэтому использую Activator.CreateInstance и у меня вот такие вещи в виде RectOffset содержатся
iprogrammer
UNец
 
Сообщения: 41
Зарегистрирован: 25 июн 2016, 07:10

Re: Чем заменить метод OnEnable()?

Сообщение ilkalawson 21 июн 2018, 17:36

^#(^ я наверное совсем отупел на первом курсе, но объясните мне зачем вы создаете экземпляры скриптовых объектов во время десериализации КАСТОМНОГО класса?

Я смотрю пример и не вижу там упоминаний о скриптовый объектах, и не могу понять зачем вы это делаете! Смотрю RectOffset и не могу понять где могла возникнуть проблема.

Или кидайте больше кода, потому что лично я пока не могу понять вообще что происходит у вас там.

Скрытый текст:
Скриптовый объекта и кастомная сериазиация классов разные вещи, одно используется вместо другого в в разных случаях и редко используется вместе.
ilkalawson
UNIверсал
 
Сообщения: 412
Зарегистрирован: 19 янв 2015, 20:38
Skype: lawsonunity

Re: Чем заменить метод OnEnable()?

Сообщение iprogrammer 21 июн 2018, 18:21

ilkalawson писал(а):^#(^ я наверное совсем отупел на первом курсе, но объясните мне зачем вы создаете экземпляры скриптовых объектов во время десериализации КАСТОМНОГО класса?

Я смотрю пример и не вижу там упоминаний о скриптовый объектах, и не могу понять зачем вы это делаете! Смотрю RectOffset и не могу понять где могла возникнуть проблема.

Или кидайте больше кода, потому что лично я пока не могу понять вообще что происходит у вас там.

Скрытый текст:
Скриптовый объекта и кастомная сериазиация классов разные вещи, одно используется вместо другого в в разных случаях и редко используется вместе.


Вы под скриптовым объектом имеете в виду ScriptableObject чтоли? Или что? Поясните.
---------------------------

У меня есть Объект EditorWindow (назовем его MainWindow), у которого отрабатывает метод OnGUI(). Есть куча тех самых классов (используется полиморфизм), у которых реализован метод Draw(), который отвечает за отрисовку объекта. В MainWindow в OnGUI рекурсивно вызывается метод Draw() у всех тех объектов. Это, я надеюсь, ответил на вопрос про скриптовые объекты
Еще раз напомню, что они НЕ отнаследованы от ScriptableObject
iprogrammer
UNец
 
Сообщения: 41
Зарегистрирован: 25 июн 2016, 07:10

Re: Чем заменить метод OnEnable()?

Сообщение ilkalawson 21 июн 2018, 19:24

у вас определенно не правильно выстроена логика - чтобы создавать классы через активатор.

Что я понял: у вас куча унаследованных кастомных классов которые вы сериализуете, при десериализации вы не знаете какой тип нужно задавать поэтому используете активатор?
В чем дело с RectOffset? Скидывайте ошибку там должно быть еще указана строка или может еще какая информация. Проблема в этой строке, верно?
Синтаксис:
Используется csharp
TestRectOffset =  new RectOffset(0, 0, 0, 0);
ilkalawson
UNIверсал
 
Сообщения: 412
Зарегистрирован: 19 янв 2015, 20:38
Skype: lawsonunity

Re: Чем заменить метод OnEnable()?

Сообщение iprogrammer 21 июн 2018, 19:43

ilkalawson писал(а):у вас определенно не правильно выстроена логика - чтобы создавать классы через активатор.

Что я понял: у вас куча унаследованных кастомных классов которые вы сериализуете, при десериализации вы не знаете какой тип нужно задавать поэтому используете активатор?
В чем дело с RectOffset? Скидывайте ошибку там должно быть еще указана строка или может еще какая информация. Проблема в этой строке
Синтаксис:
Используется csharp
TestRectOffset =  new RectOffset(0, 0, 0, 0);



Хех, вы проницательны)) Вот только я всё это, включая текст ошибки описал в самом первом своем сообщении :D
iprogrammer
UNец
 
Сообщения: 41
Зарегистрирован: 25 июн 2016, 07:10

Re: Чем заменить метод OnEnable()?

Сообщение ilkalawson 21 июн 2018, 23:19

текст ошибки описал в самом первом своем сообщении

обычно пишется еще строка в которой происходит ошибка, у меня вот так
Скрытый текст:
Изображение


сам код
Синтаксис:
Используется csharp
public class Test : MonoBehaviour {

 public SS s;

}

[System.Serializable]
public class SS : ISerializationCallbackReceiver {

 public string name = "Some name";
 public int number = 3;

 public void OnAfterDeserialize() {
  RectOffset offset = new RectOffset(0, 0, 0, 0);
 }

 public void OnBeforeSerialize() {

 }

}


Можно создавать экземпляры через конструктор без параметров new RectOffset(), а задавать отступ(left, right и тд.) не получиться. Видимо там зависимости от других компонентов, и поэтому при десериализации, когда объекты проходят эту процедуру в проекте, нет доступа к необходимым параметрам.

Первое что приходит на ум - использовать простой Rect и по нему уже потом при отрисовке создавать RectOffset.

Кстати очень много лишней инфы даете в описании проблемы, ошибка конкретно в задании параметров экземпляра RectOffset, без всяких там кастомных и скриптовых объектов.
ilkalawson
UNIверсал
 
Сообщения: 412
Зарегистрирован: 19 янв 2015, 20:38
Skype: lawsonunity

Re: Чем заменить метод OnEnable()?

Сообщение iprogrammer 25 июн 2018, 13:15

ilkalawson писал(а):обычно пишется еще строка в которой происходит ошибка, у меня вот так
Скрытый текст:
Изображение



Просто находясь постоянно на Stackoverflow.com я привык оформлять текст ошибки цитатой, а не картинкой)) так и другим удобно, порой, если нужно, скопировать её текст, а не мучиться срисовывать текст :)
Тоже самое касается "много лишней инфы даете в описании проблемы". Видимо привык подробно описывать, чтоб не клевали))

ilkalawson писал(а):Можно создавать экземпляры через конструктор без параметров new RectOffset(), а задавать отступ(left, right и тд.) не получиться. Видимо там зависимости от других компонентов, и поэтому при десериализации, когда объекты проходят эту процедуру в проекте, нет доступа к необходимым параметрам. Первое что приходит на ум - использовать простой Rect и по нему уже потом при отрисовке создавать RectOffset.


Да я думал, но это получится чуть ли не двойная десериализация: часть полей там, часть там. Да и в принципе это уже нарушение SOLID, где класс занимается не тем, чем он должен.
Вообще в исходниках юнити зависимостей никаких нет. Есть object sourceStyle, но он итак сериализуемый.

Вообще пока сделал свой примитивный класс RectOffsetSeralizable:

Синтаксис:
Используется csharp
[Serializable]
public class RectOffsetSeralizable {
        public int Top { get; set; }
        public int Left { get; set; }
        public int Right { get; set; }
        public int Bottom { get; set; }

        public RectOffsetSeralizable() : this(0, 0, 0, 0) { }

        public RectOffsetSeralizable(RectOffset rectOffset) {
                Top = rectOffset.top;
                Bottom = rectOffset.bottom;
                Left = rectOffset.left;
                Right = rectOffset.right;
        }


        public RectOffsetSeralizable(int left, int right, int top, int bottom) {
                Top = top;
                Bottom = bottom;
                Left = left;
                Right = right;
        }


        public RectOffset ToRectOffset() {
                return new RectOffset(Left, Right, Top, Bottom);
        }


        public override string ToString() {
                return $"RectOffset (l:{Left} r:{Right} t:{Top} b:{Bottom})";
        }
}
 


Это, конечно, работает, но если будут еще разные классы, объекты которых нужно инициализировать в OnEnable() , то это грустно, ибо куча костылей...
Я вообще не понимаю зачем Unity разработчики сделали такой изврат. Есть уже и Awake и Start и тут еще OnEnable.
iprogrammer
UNец
 
Сообщения: 41
Зарегистрирован: 25 июн 2016, 07:10


Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15