Виртуальный метод вызывается вместо переопределения - PullRequest
0 голосов
/ 04 октября 2018

У меня есть четыре класса, Event и Action, которые оба являются базовыми классами, и затем у меня есть два дочерних класса Create : Event и MoveTo : Action.

Event содержит список Action экземпляров, и когда Trigger() вызывается в дочернем элементе Create, он вызывает Event.Trigger(), который перебирает список действий, и вызывает Action.Run() для каждого действия, которое вызывает Called().

У меня проблема в том, что вызывается метод virtual, а не метод override внутри MoveTo.

[Serializable]
public abstract class Event : MonoBehaviour {
  [SerializeField] public List<Action> actions = new List<Action>();

  protected void Trigger() {
    foreach (Action action in actions) {
      action.Run();
    }
  }
}

Событие

public class Create : Event {
  void Start() {
    Trigger();
  }
}

Действие

[Serializable]
public class Action {
  public virtual void Called() {
    Debug.Log("Virtual");
  }

  public void Run() {
    Called();
  }
}

MoveTo

public class MoveTo : Action {
  public override void Called() {
    Debug.Log("Called");
  }
}

Я добавляю действие MoveTo в список событий из редактора Unity на префаб.Я не уверен, как единство обрабатывает их во время выполнения, инициализирует их или нет?В этом я не уверен.Вот что может быть причиной моей проблемы ...

private Event GetCurrentEvent(){}

void AddActionCallback(Type actionType) {
  // actionType is MoveTo
  var prefab = GetCurrentPrefabItem().Value;
  var evt = GetCurrentEvent();
  evt.actions.Add((Action)Activator.CreateInstance(actionType));
  Undo.RecordObject(prefab.gameObject, "Added actions");
  PrefabUtility.RecordPrefabInstancePropertyModifications(prefab.gameObject);
}

Вот как это выглядит до запуска игры.Показывает MoveTo, кнопка в красном столбце показывает действие, используя action.GetType().Name.Это имя до запуска игры:

before

После запуска игры кнопка теперь выглядит так:

after

При работе:

evt.actions.Add((Action)Activator.CreateInstance(actionType));

Редактор отображает Несоответствие типов , даже если выходные данные actionType и Activator.CreateInstance(actionType)MoveTo:

type mismatch

1 Ответ

0 голосов
/ 05 октября 2018

Unity не поддерживает встроенную полиморфную сериализацию .

Когда вы сохраняете префаб, он сериализует Список как список чистых Action с и удаляет любую информацию, котораяимеет только дочерний класс MoveTo.

Из документов Unity по сериализации :

Нет поддержки полиморфизма

Если у вас есть public Animal[] animals и вы положили вэкземпляр Dog, Cat и Giraffe, после сериализации у вас есть три экземпляра Animal.

Один из способов справиться с этим ограничением - это осознать, что оно относится только кпользовательские классы, которые сериализуются внутри строки.Ссылки на другие UnityEngine.Objects сериализуются как фактические ссылки, и для них полиморфизм действительно работает.Вы должны создать ScriptableObject производный класс или другой MonoBehaviour производный класс и сослаться на него.Недостатком этого является то, что вам нужно где-то хранить этот Monobehaviour или scriptable объект, и что вы не можете эффективно его сериализовать внутри строки.

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

Именно поэтому его класс отображается как Action.

Однако он не может сериализоваться как Action , потому что :

Как обеспечить сериализацию пользовательского класса

Убедитесь, что:

  • Имеет атрибут Serializable

  • Не является абстрактным

  • Не является статичным

  • Не является универсальным, хотя может наследоваться от универсального класса

Action является абстрактным классом, поэтому он выигралдаже сериализовать частично правильно.Я предполагаю, что это является основной причиной проблемы Type Mismatch, поскольку Unity пытается десериализовать что-либо, что не поддерживается.

Короче говоря, если вы хотите сериализовать данные в MoveTo, вам нужноиметь [SerializeField] List<MoveTo>, чтобы не потерять информацию, или вы можете иметь Action наследовать от ScriptableObject, что приносит свои проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...