The same field name is serialized multiple times in the class or its parent class. Как исправить ошибку?
У меня есть компонент Entity
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _scriptableObject; public EntityScriptableObject ScriptableObject => _scriptableObject; } |
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _scriptableObject; public EntityScriptableObject ScriptableObject => _scriptableObject; }
И класс Document который от него унаследован
public class Document : Entity { [SerializeField] private DocumentScriptableObject _scriptableObject; public new DocumentScriptableObject ScriptableObject => _scriptableObject; } |
public class Document : Entity { [SerializeField] private DocumentScriptableObject _scriptableObject; public new DocumentScriptableObject ScriptableObject => _scriptableObject; }
С Entity проблем не возникает, но вот при добавлении компонента Document на объект Unity выдаёт такую ошибку:
The same field name is serialized multiple times in the class or its parent class. This is not supported: Base(MonoBehaviour) _scriptableObject.
Также в инспекторе дублируется поле _scriptableObject
Как я понимаю проблема возникает из-за того что поля с одинаковым названием я пытаюсь сериализовать в базовом и наследуемом классах. Возникает вопрос можно ли (и нужно ли) исправить эту ошибку, ведь код, судя по всему, компилируется и работает так как я и задумывал. Также меня больше беспокоит то что в инспекторе дублируются поля, хотя когда я пытаюсь передать туда ссылку на объект то она передается в оба поля сразу. Это баг юнити или это из-за того что я не скрываю поле базового класса? Если дело в этом то почему тогда тип полей одинаковый в инспекторе хотя в базовом и наследуемом классах они разные? Не вызовет ли это проблем в дальнейшем если так это и оставить?
Дополнительно:
Можно сделать разные имена полей в базовом и производном классах
Теперь из-за того что поле базового класса также сериализуется - в инспекторе появляются оба поля из базового класса и из класса компонента. Мой код не предполагает что в компоненте Document я могу использовать ссылку другого типа кроме DocumentScriptableObject. А если просто оставить поле пустым, то при взаимодействии с объектом летят NullReferenceException-ы. Я пробовал скрывать поле базового класса делая его protected, а в наследуемом классе использовал модификатор new. Но тогда возвращается первая проблема с ошибкой сериализации
Возникает вопрос можно ли (и нужно ли) исправить эту ошибку, ведь код, судя по всему, компилируется и работает так как я и задумывал.
А какую задачу ты решаешь? Почему два разных поля (в родительском и дочернем классе и с разными типами) имеют одно и то же имя?
Теперь из-за того что поле базового класса также сериализуется - в инспекторе появляются оба поля из базового класса и из класса компонента.
Если для тебя это проблема, значит изначально у тебя были архитектурные проблемы.
Вместо класса, вероятно, тебе нужно использовать интерфейс в котором будет обобщённое свойство для ScriptableObject
если еще не нашли решения..
и сложно придумать другую "архитектуру".. вопросы:
- дерево родителя и потомков? если есть иерархия более одного уровня:
- у вас может быть ошибка в последовательности выяснения "потомка"
- имхо один родитель, при чем virtual
- использование интерфейсов (но не конфликт имени/типа поля!! ;)
- и гарантия десирализации в нужный класс
.. вы же пытаетесь сделать нечто вроде конвейера "скриптования"? (очень очень много лет назад пытался использовать такой подход.. мое работало )).. но TVision приехал очень быстро.. и наработки потеряли смысл )))
- Я решил всё-таки немного изменить архитектуру, так как основная проблема была в ней, а всё остальное и, в том числе ошибка в юнити возникало уже как следствие. Может кому-то окажется полезным, не уверен насколько эта идея лучше, но для логики которую я задумал рабочим вариантом стало такое решение:
Я избавился от наследования классов ScriptableObject, так что теперь иерархию наследования имеют только объекты Entity, Item и Document.
public class EntityScriptableObject : ScriptableObject { [SerializeField] private EntityType _type; [SerializeField] private string _name; [SerializeField] private string _raycastFeedbackText; [SerializeField] private GameObject _prefab; public EntityType Type => _type; public string Name => _name; public string RaycastFeedbackText => _raycastFeedbackText; public GameObject Prefab => _prefab; }
public class EntityScriptableObject : ScriptableObject { [SerializeField] private EntityType _type; [SerializeField] private string _name; [SerializeField] private string _raycastFeedbackText; [SerializeField] private GameObject _prefab; public EntityType Type => _type; public string Name => _name; public string RaycastFeedbackText => _raycastFeedbackText; public GameObject Prefab => _prefab; }
public class ItemScriptableObject : ScriptableObject { [SerializeField] private ItemType _type; [SerializeField] private string _description; [SerializeField] private string _raycastFeedbackText; [SerializeField] private Sprite _sprite; public ItemType Type => _type; public string Description => _description; public string RaycastFeedbackText => _raycastFeedbackText; public Sprite Sprite => _sprite; }
public class ItemScriptableObject : ScriptableObject { [SerializeField] private ItemType _type; [SerializeField] private string _description; [SerializeField] private string _raycastFeedbackText; [SerializeField] private Sprite _sprite; public ItemType Type => _type; public string Description => _description; public string RaycastFeedbackText => _raycastFeedbackText; public Sprite Sprite => _sprite; }
public class DocumentScriptableObject : ScriptableObject { [SerializeField] private DocumentType _type; [SerializeField] private string _text; [SerializeField] private string _raycastFeedbackText; public DocumentType Type => _type; public string Text => _text; public string RaycastFeedbackText => _raycastFeedbackText; }
public class DocumentScriptableObject : ScriptableObject { [SerializeField] private DocumentType _type; [SerializeField] private string _text; [SerializeField] private string _raycastFeedbackText; public DocumentType Type => _type; public string Text => _text; public string RaycastFeedbackText => _raycastFeedbackText; }
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _entityScriptableObject; public EntityScriptableObject EntityScriptableObject => _entityScriptableObject; public virtual void Interact(){} public void StopInteraction(){} }
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _entityScriptableObject; public EntityScriptableObject EntityScriptableObject => _entityScriptableObject; public virtual void Interact(){} public void StopInteraction(){} }
public class Item : Entity { [SerializeField] private ItemScriptableObject _itemScriptableObject; public ItemScriptableObject ItemScriptableObject => _itemScriptableObject; public Item (ItemScriptableObject scriptableObject) { _itemScriptableObject = scriptableObject; } public void Use(){} public override void Interact(){} }
public class Item : Entity { [SerializeField] private ItemScriptableObject _itemScriptableObject; public ItemScriptableObject ItemScriptableObject => _itemScriptableObject; public Item (ItemScriptableObject scriptableObject) { _itemScriptableObject = scriptableObject; } public void Use(){} public override void Interact(){} }
public class Document : Entity { [SerializeField] private DocumentScriptableObject _documentScriptableObject; public DocumentScriptableObject DocumentScriptableObject => _documentScriptableObject; public void Read(){} public override void Interact(){} }
public class Document : Entity { [SerializeField] private DocumentScriptableObject _documentScriptableObject; public DocumentScriptableObject DocumentScriptableObject => _documentScriptableObject; public void Read(){} public override void Interact(){} }
Метод Interact в наследниках переопределяю так как по задумке объект одного и того же типа (например ключ) может как быть предметом, и его можно будет подобрать и использовать, так может и просто лежать где-нибудь, но подобрать его уже нельзя, хотя всё ещё можно как-либо взаимодействовать, например осмотреть.
- Gwinterion, стабильно работает? ))
так держать! ;) - Gwinterion, ну и мало ли.. если не видели https://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%B1%D...
.. это не единственная парадигма, но именно для конвейера стоит понимать ;)
Ответы:
Простите, пожалуйста, но это очень глупый вопрос. Вы C# вообще учили?
Вот ваш класс:
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _scriptableObject; public EntityScriptableObject ScriptableObject => _scriptableObject; } |
public class Entity : MonoBehaviour { [SerializeField] private EntityScriptableObject _scriptableObject; public EntityScriptableObject ScriptableObject => _scriptableObject; }
И вам же четко пишет, что у вас два поля с одинаковыми именами. Вот:
[SerializeField] private EntityScriptableObject _scriptableObject; |
[SerializeField] private EntityScriptableObject _scriptableObject;
И вот:
public EntityScriptableObject ScriptableObject => _scriptableObject; |
public EntityScriptableObject ScriptableObject => _scriptableObject;
- Если вы хотели привести в пример два поля, то привели в пример поле и свойство. Это разные вещи... И ошибка не в этом, у них даже имена разные
- Gwinterion, действительно разные?
- Gwinterion, я знаю, что поле и свойство это разные вещи, так у вас не может быть два элемента с одинаковыми именам
- Nik Faraday, Так то что вы выделили это вообще тип а не имя
-
И вам же четко пишет, что у вас два поля с одинаковыми именами. Вот:
[SerializeField] private EntityScriptableObject _scriptableObject;И вот:
public EntityScriptableObject ScriptableObject => _scriptableObject;Погоди, но имена у них разные.
1. _scriptableObject
2. ScriptableObject
А второе - вообще свойство, а не поле.
И ошибка идёт не от компилятора C#, а от Unity - Nik Faraday, на скриншоте выделены типы, а не имена.
- Василий Банников, Gwinterion, да, тут прошу прощения, утром не проснулся) Моя ошибка
- Василий Банников, тем не менее, первое желание - понять целевую логику..
второе - упростить ее, по возможности
... пока что все от ТС не очень этому способствует - Василий Банников,
[SerializeField] private EntityScriptableObject _scriptableObject;
[SerializeField] private EntityScriptableObject _scriptableObject;
[SerializeField] private DocumentScriptableObject _scriptableObject;
[SerializeField] private DocumentScriptableObject _scriptableObject;
- Василий Банников, я может тоже "не проснулся".. но в обоих объявлениях, до сих пор вижу одно имя
- Василий Банников, да еще и декларацию с разным типом... или атрибутам такое позволено?
- #, ну так одно в родительском, а другое в дочернем.
- Василий Банников, ... если это атрибут ))
- #, не понимаю. Атрибут тут никак не влияет.
- Василий Банников, но и не метод... поля разве уже можно переопределять? ))
- #, нельзя. Просто будет отдельно base._fieldName и this._fieldName
- Василий Банников, полагаете, в данном случае строгости Unity?
- #, постараюсь объяснить логику которую задумал :)
Все объекты в сцене с которыми может взаимодействовать игрок - это некие сущности Entity. Есть также наследуемые объекты Item и Document.
public class Entity : MonoBehaviour { [field: SerializeField] public virtual EntityScriptableObject ScriptableObject { get; private set; } public void Interact() { Transform interactionPoint; switch (ScriptableObject.Type) { case EntityType.Key: Player.Inventory.Add(this as Item); Destroy(gameObject); break; case EntityType.VideoTape: Player.Inventory.Add(this as Item); Destroy(gameObject); break; case EntityType.Note: Player.Journal.Add(this as Document); Destroy(gameObject); break; case EntityType.Painting: GameManager.ChangeTypeOfControll(TypesOfControl.InspectionControll); ObjectInspectorController.Instance.enabled = true; ObjectInspectorController.Instance.Initialize(this); break; case EntityType.TV: GameManager.PauseGame(); interactionPoint = InteractionPoints.Instance.TV.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.TV; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; UIController.Instance.OpenInventory(); PlayerController.Instance.enabled = false; break; case EntityType.Door: DoorController door = gameObject.GetComponent<DoorController>(); if (door.IsOpen) door.CloseDoor(); else door.OpenDoor(); break; case EntityType.SafeDigital: GameManager.PauseGame(); GameManager.ChangeTypeOfControll(TypesOfControl.InteractionControl); interactionPoint = InteractionPoints.Instance.SafeDigital.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.SafeNumeric; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; PlayerController.Instance.enabled = false; CameraController.Instance.enabled = false; Cursor.lockState = CursorLockMode.None; Cursor.visible = true; gameObject.GetComponentInChildren<SafeDoor>().enabled = true; break; case EntityType.SafePadlock: GameManager.PauseGame(); GameManager.ChangeTypeOfControll(TypesOfControl.InteractionControl); interactionPoint = InteractionPoints.Instance.SafePadlock.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.SafePadlock; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; PlayerController.Instance.enabled = false; CameraController.Instance.enabled = false; Cursor.lockState = CursorLockMode.None; Cursor.visible = true; gameObject.GetComponentInChildren<Padlock>().enabled = true; break; default: break; } } public void StopInteraction() { switch (ScriptableObject.Type) { case EntityType.Key: break; case EntityType.VideoTape: break; case EntityType.Note: break; case EntityType.Painting: break; case EntityType.TV: InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.ReturnToInteractionPosition(); InteractionController.Instance.CurrentInteraction = InteractionType.None; GameManager.ResumeGame(); break; case EntityType.Door: break; case EntityType.SafeDigital: gameObject.GetComponentInChildren<SafeDoor>().enabled = false; Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; PlayerController.Instance.enabled = true; CameraController.Instance.enabled = true; InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.CurrentInteraction = InteractionType.None; InteractionController.Instance.ReturnToInteractionPosition(); GameManager.ChangeTypeOfControll(TypesOfControl.PlayerControl); GameManager.ResumeGame(); break; case EntityType.SafePadlock: Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; PlayerController.Instance.enabled = true; CameraController.Instance.enabled = true; InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.CurrentInteraction = InteractionType.None; InteractionController.Instance.ReturnToInteractionPosition(); GameManager.ChangeTypeOfControll(TypesOfControl.PlayerControl); GameManager.ResumeGame(); break; default: break; } } }
public class Entity : MonoBehaviour { [field: SerializeField] public virtual EntityScriptableObject ScriptableObject { get; private set; } public void Interact() { Transform interactionPoint; switch (ScriptableObject.Type) { case EntityType.Key: Player.Inventory.Add(this as Item); Destroy(gameObject); break; case EntityType.VideoTape: Player.Inventory.Add(this as Item); Destroy(gameObject); break; case EntityType.Note: Player.Journal.Add(this as Document); Destroy(gameObject); break; case EntityType.Painting: GameManager.ChangeTypeOfControll(TypesOfControl.InspectionControll); ObjectInspectorController.Instance.enabled = true; ObjectInspectorController.Instance.Initialize(this); break; case EntityType.TV: GameManager.PauseGame(); interactionPoint = InteractionPoints.Instance.TV.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.TV; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; UIController.Instance.OpenInventory(); PlayerController.Instance.enabled = false; break; case EntityType.Door: DoorController door = gameObject.GetComponent<DoorController>(); if (door.IsOpen) door.CloseDoor(); else door.OpenDoor(); break; case EntityType.SafeDigital: GameManager.PauseGame(); GameManager.ChangeTypeOfControll(TypesOfControl.InteractionControl); interactionPoint = InteractionPoints.Instance.SafeDigital.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.SafeNumeric; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; PlayerController.Instance.enabled = false; CameraController.Instance.enabled = false; Cursor.lockState = CursorLockMode.None; Cursor.visible = true; gameObject.GetComponentInChildren<SafeDoor>().enabled = true; break; case EntityType.SafePadlock: GameManager.PauseGame(); GameManager.ChangeTypeOfControll(TypesOfControl.InteractionControl); interactionPoint = InteractionPoints.Instance.SafePadlock.transform; InteractionController.Instance.InteractionPoint = interactionPoint; InteractionController.Instance.CurrentInteraction = InteractionType.SafePadlock; InteractionController.Instance.MoveToInteractionPoint(); InteractionController.Instance.OnStopInteraction += StopInteraction; PlayerController.Instance.enabled = false; CameraController.Instance.enabled = false; Cursor.lockState = CursorLockMode.None; Cursor.visible = true; gameObject.GetComponentInChildren<Padlock>().enabled = true; break; default: break; } } public void StopInteraction() { switch (ScriptableObject.Type) { case EntityType.Key: break; case EntityType.VideoTape: break; case EntityType.Note: break; case EntityType.Painting: break; case EntityType.TV: InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.ReturnToInteractionPosition(); InteractionController.Instance.CurrentInteraction = InteractionType.None; GameManager.ResumeGame(); break; case EntityType.Door: break; case EntityType.SafeDigital: gameObject.GetComponentInChildren<SafeDoor>().enabled = false; Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; PlayerController.Instance.enabled = true; CameraController.Instance.enabled = true; InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.CurrentInteraction = InteractionType.None; InteractionController.Instance.ReturnToInteractionPosition(); GameManager.ChangeTypeOfControll(TypesOfControl.PlayerControl); GameManager.ResumeGame(); break; case EntityType.SafePadlock: Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; PlayerController.Instance.enabled = true; CameraController.Instance.enabled = true; InteractionController.Instance.OnStopInteraction -= StopInteraction; InteractionController.Instance.CurrentInteraction = InteractionType.None; InteractionController.Instance.ReturnToInteractionPosition(); GameManager.ChangeTypeOfControll(TypesOfControl.PlayerControl); GameManager.ResumeGame(); break; default: break; } } }
public class Item : Entity { [SerializeField] private ItemScriptableObject _scriptableObject; public override EntityScriptableObject ScriptableObject => _scriptableObject; public void Use() { switch (_scriptableObject.Type) { case EntityType.Key: Player.Inventory.Remove(this); Debug.Log("Key used."); break; case EntityType.VideoTape: if (InteractionController.Instance.CurrentInteraction != InteractionType.TV) return; Player.Inventory.Remove(this); Debug.Log("Tape inserted."); break; case EntityType.Note: break; case EntityType.Painting: break; case EntityType.TV: break; case EntityType.Door: break; case EntityType.SafeDigital: break; case EntityType.SafePadlock: break; default: break; } } }
public class Item : Entity { [SerializeField] private ItemScriptableObject _scriptableObject; public override EntityScriptableObject ScriptableObject => _scriptableObject; public void Use() { switch (_scriptableObject.Type) { case EntityType.Key: Player.Inventory.Remove(this); Debug.Log("Key used."); break; case EntityType.VideoTape: if (InteractionController.Instance.CurrentInteraction != InteractionType.TV) return; Player.Inventory.Remove(this); Debug.Log("Tape inserted."); break; case EntityType.Note: break; case EntityType.Painting: break; case EntityType.TV: break; case EntityType.Door: break; case EntityType.SafeDigital: break; case EntityType.SafePadlock: break; default: break; } } }
public class Document : Entity { [SerializeField] private DocumentScriptableObject _scriptableObject; public override EntityScriptableObject ScriptableObject => _scriptableObject; public void Read() { switch (ScriptableObject.Type) { case EntityType.Key: break; case EntityType.VideoTape: break; case EntityType.Note: DocumentInspectorController.Instance.enabled = true; DocumentInspectorController.Instance.Initialize(_scriptableObject.Text); break; case EntityType.Painting: break; case EntityType.TV: break; case EntityType.Door: break; case EntityType.SafeDigital: break; case EntityType.SafePadlock: break; default: break; } } }
public class Document : Entity { [SerializeField] private DocumentScriptableObject _scriptableObject; public override EntityScriptableObject ScriptableObject => _scriptableObject; public void Read() { switch (ScriptableObject.Type) { case EntityType.Key: break; case EntityType.VideoTape: break; case EntityType.Note: DocumentInspectorController.Instance.enabled = true; DocumentInspectorController.Instance.Initialize(_scriptableObject.Text); break; case EntityType.Painting: break; case EntityType.TV: break; case EntityType.Door: break; case EntityType.SafeDigital: break; case EntityType.SafePadlock: break; default: break; } } }
Так как Item содержит метод Use, а Document содержит метод Read, читать можно только объекты типа Document, использовать только Item, а взаимодействовать с любыми Entity. Изначально классы этих объектов были абстрактными и содержали свойства которые описывали эти объекты (название, описание, спрайт и т.д.), и от каждого объекта наследовали уже конкретные классы. Например от класса Item наследовали классы Key и VidoTape. Для хранения данных всех сущностей я изначально использовал использовал статический класс единственным свойством, которое являлось Dictionary. В нём я создавал экземпляры классов и через конструкторы задавал им свойства. Но сейчас для удобства решил вместо этого как хранилище данных использовать ScriptableObject-ы. А весь функционал реализовать в классах которые до этого были абстрактными используя switch по типам сущностей.
- #, Вот код классов ScriptableObject.
public class EntityScriptableObject : ScriptableObject { [SerializeField] private EntityType _type; [SerializeField] private string _displayName; [SerializeField] private string _description; [SerializeField] private string _raycastFeedbackText; [SerializeField] private GameObject _prefab; public EntityType Type => _type; public string DisplayName => _displayName; public string Description => _description; public string RaycastFeedbackText => _raycastFeedbackText; public GameObject Prefab => _prefab; }
public class EntityScriptableObject : ScriptableObject { [SerializeField] private EntityType _type; [SerializeField] private string _displayName; [SerializeField] private string _description; [SerializeField] private string _raycastFeedbackText; [SerializeField] private GameObject _prefab; public EntityType Type => _type; public string DisplayName => _displayName; public string Description => _description; public string RaycastFeedbackText => _raycastFeedbackText; public GameObject Prefab => _prefab; }
public class ItemScriptableObject : EntityScriptableObject { [SerializeField] private Sprite _sprite; public Sprite Sprite => _sprite; }
public class ItemScriptableObject : EntityScriptableObject { [SerializeField] private Sprite _sprite; public Sprite Sprite => _sprite; }
public class DocumentScriptableObject : EntityScriptableObject { [SerializeField] private string _text; public string Text => _text; }
public class DocumentScriptableObject : EntityScriptableObject { [SerializeField] private string _text; public string Text => _text; }
По идее данная реализация не предполагает что допустим в объект типа Document может попасть ссылка на ItemScriptableObject. Так что я пытался явно указать ссылки каких типов может принимать тот или иной объект но столкнулся с проблемами описанными выше
- Gwinterion, одним словом, переименнуюйте _scriptableObject во что-то другое, что бы не было конфликта имён
- Nik Faraday, Gwinterion, склонен поддержать..
- Василий Банников, спасибо за ликбез.. но есть сомнения, всегда ли это удобно..
- Gwinterion, далее [SerializeField] с одним именем для родителя и потомка, еще более сомнительно. если сериализуете, то как десериализуете? в конкретный тип? или в object? или есть автоопределение?
... если не очень "авто", то конфликт типов все более вероятен.. - Gwinterion,
постараюсь объяснить логику которую задумал :)
ок. благие намерения в целом все более понятны..
во что сериализуете? json/bson/bd?
у вас львиная часть кода пытается определить "а что мы десериализовали"?
.. и учитывая количество ветвлений, риск ошибки уж больно быстро растет..
(пока не предлагаю решений, просто пытаюсь увидеть слабое место - Gwinterion,
Вместо класса, вероятно, тебе нужно использовать интерфейс в котором будет обобщённое свойство для ScriptableObject
от Василий Банников, скорее ближе к решению.. но
во что сериализуете? json/bson/bd?
не снимется..
.. был у меня случай с litedb, несколько лет назад.. требовалось компактное встроенное решение.. облом случился на десериализации, кажется массива строк.. решил не тут, дебагером.. но и не юнити, в студии комьюнити..
.. заменил на json и забыл о проблеме..ps вспомнил - двумерный массив строк, десереализовался в одномерный... обидно было ))
- Gwinterion, ну и "топорный вариант" - сериализовать строго по типам (бд - таблицы, json - да хоть файлы)..
если очередность "скриптабельных" объектов, при восстановлении, имеет значение - метки времени?..
... может это поможет обойти "узкое" место?... отработать дальнейшую логику.. а к этому вопросу возвращаться по мере роста эрудиции/навыков? .. удачи )) - Gwinterion, ну и возможно, даже макет, если продебажить в студии.. не факт что это одно и тоже с юнинити... если не подводит память - юнити основан на mono (далее кросскомпиляция в плюсы, потом в бинарный код)...
... если бы юнити поддерживал консольные и асп проекты... я бы давно переехал туда )))
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос




Для исправления ошибки, когда одно и то же имя поля сериализуется несколько раз в классе или его родительском классе, вам необходимо внимательно просмотреть структуру классов и убедиться, что каждое поле имеет уникальное имя.
Один из распространенных случаев, когда такая ошибка может возникнуть, это когда вы объявляете одно и то же поле в дочернем классе, которое уже объявлено в родительском классе. В этом случае вам следует переопределить это поле в дочернем классе с другим именем.
Пример:
class ParentClass { public $field = 'parent'; } class ChildClass extends ParentClass { public $field = 'child'; // переопределение поля }
Если у вас несколько родительских классов, в которых объявлено одно и то же поле, убедитесь, что в каждом дочернем классе, которые наследуют эти родительские классы, поле переопределено с уникальным именем.
Также стоит убедиться, что вы правильно используете механизм сериализации в PHP, чтобы избежать дублирования данных при сериализации объекта. При сериализации объекта PHP сериализует только данные, которые находятся в свойствах объекта, но не в его методах.
Надеюсь, эти советы помогут вам исправить ошибку с дублированием имени поля при сериализации объекта в PHP. Если у вас остались вопросы, пожалуйста, не стесняйтесь задавать их для получения более подробной помощи.