调用虚拟方法而不是重写

时间:2018-10-04 18:55:03

标签: c# unity3d

我有四个类,EventAction都是基类,然后有两个子类Create : EventMoveTo : 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 Editor的事件列表添加到预制上。我不确定运行时如何统一处理这些,是初始化它们还是执行?我不确定。那可能是导致我的问题的原因...

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));

即使actionTypeActivator.CreateInstance(actionType)的输出为MoveTo,编辑器也会显示类型不匹配

type mismatch

1 个答案:

答案 0 :(得分:1)

Unity does not support built-in polymorphic serialization

保存预制件时,它会将List序列化为纯Action的列表,并删除仅子类MoveTo拥有的所有信息。

来自Unity docs on serialization

  

不支持多态性

     

如果您有public Animal[] animals并且   您将DogCatGiraffe的实例放在   序列化,您有三个Animal的实例。

     

处理此限制的一种方法是认识到它仅   适用于自定义类,该类可以内联序列化。参考   其他UnityEngine.Objects被序列化为实际引用,并且对于   这些,多态性确实有效。你会做一个   ScriptableObject派生类或另一个MonoBehaviour派生类,   并参考。缺点是您需要存储   Monobehaviourscriptable的某个地方,而您不能   有效地内联序列化它。

     

这些限制的原因是核心基础之一   序列化系统的特点是   提前知道一个物体;这取决于类型   类的字段,而不是存储在   字段。

这就是为什么其类显示为Action的原因。

但是,它不能序列化为Action because

  

如何确保自定义类可以序列化

     

确保:

     
      
  • 具有Seri​​alizable属性

  •   
  • 不是抽象

  •   
  • 不是静态的

  •   
  • 不是通用类,尽管它可能继承自通用类

  •   

Action是一个抽象类,因此它甚至无法部分正确地序列化。我认为这是Type Mismatch问题的根本原因,因为Unity正在努力反序列化一些不受支持的内容。

简而言之,如果要序列化MoveTo中的数据,则需要有一个[SerializeField] List<MoveTo>,以免丢失信息,或者可以使Action继承来自ScriptableObject,带来了自己的问题。