调用虚拟方法而不是重写 [英] Virtual method getting called instead of the override

查看:198
本文介绍了调用虚拟方法而不是重写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有四个类,分别是基类EventAction,然后有两个子类Create : EventMoveTo : Action.

I have four classes, Event and Action which are both base classes, and then I have two child classes Create : Event and MoveTo : Action.

Event包含一个Action实例的列表,并且在子Create子级中调用Trigger()时,它会调用Event.Trigger(),这会遍历操作列表,并在每个操作上调用Action.Run()会调用Called().

Event contains a list of Action instances, and when Trigger() is called in the child Create it calls Event.Trigger(), which loops over the list of actions, and calls Action.Run() on each action which calls Called().

我遇到的问题是virtual方法被调用,而不是MoveTo内部的override方法.

The Issue I am having is the virtual method is getting called and not the override method inside of 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的事件列表添加到预制件上.我不确定运行时如何统一处理这些,是否初始化它们还是我要这样做?我不确定.那可能是导致我的问题的原因...

I am adding the MoveTo action to the event list from the Unity Editor onto a prefab. I am not sure how unity handles these at runtime, does in initialize them or do I? That I am not sure about. That is what might be causing my issue...

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的操作.这是我运行游戏之前的名称:

Here is what it looks like before I run the game. It shows MoveTo, the button in the red column shows the action using action.GetType().Name. This is the name before I run the game:

运行游戏后,按钮现在看起来像这样:

After I run the game the button now looks like this:

运行时:

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

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

The editor displays Type mismatch even when the output of actionType and Activator.CreateInstance(actionType) is MoveTo:

推荐答案

团结不支持内置的多态序列化..

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

Unity does not support built-in polymorphic serialization.

When you save the prefab, it serializes the List as a list of pure Actions, and erases any information that only the child class MoveTo has.

从Unity 有关序列化的文档:

不支持多态性

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

No support for polymorphism

If you have a public Animal[] animals and you put in an instance of aDog, a Cat and a Giraffe, after serialization, you have three instances of Animal.

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

One way to deal with this limitation is to realize that it only applies to custom classes, which get serialized inline. References to other UnityEngine.Objects get serialized as actual references, and for those, polymorphism does actually work. You would make a ScriptableObject derived class or another MonoBehaviour derived class, and reference that. The downside of this is that you need to store that Monobehaviour or scriptable object somewhere, and that you cannot serialize it inline efficiently.

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

The reason for these limitations is that one of the core foundations of the serialization system is that the layout of the datastream for an object is known ahead of time; it depends on the types of the fields of the class, rather than what happens to be stored inside the fields.

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

This is why its class shows up as an Action.

但是,它不能序列化为Action 因为 :

However, it can't serialize as an Action because:

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

确保:

How to ensure a custom class can be serialized

Ensure it:

  • 具有可序列化"属性

  • Has the Serializable attribute

不是抽象

不是静态的

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

Is not generic, though it may inherit from a generic class

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

Action is an abstract class, so it won't even serialize partially properly. I assume this is the root cause of the Type Mismatch problem, as Unity is struggling to deserialize something that is unsupported.

简而言之,如果要序列化MoveTo中的数据,则必须具有[SerializeField] List<MoveTo>才能丢失信息,或者可以使Action从ScriptableObject继承,带来了自己的问题.

In short, if you want to serialize data in MoveTo, you'll need to have a [SerializeField] List<MoveTo> in order to not lose the information, or you can have Action inherit from ScriptableObject, which brings its own problems.

这篇关于调用虚拟方法而不是重写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆