调用虚拟方法而不是重写 [英] Virtual method getting called instead of the override
问题描述
我有四个类,分别是基类Event
和Action
,然后有两个子类Create : Event
和MoveTo : 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));
即使actionType
和Activator.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 Action
s, and erases any information that only the child class MoveTo
has.
从Unity 有关序列化的文档:
不支持多态性
如果您有
public Animal[] animals
并且 您将Dog
,Cat
和Giraffe
的实例放在 序列化,您有三个Animal
实例.
No support for polymorphism
If you have a
public Animal[] animals
and you put in an instance of aDog
, aCat
and aGiraffe
, after serialization, you have three instances ofAnimal
.
处理此限制的一种方法是认识到它仅
适用于自定义类,该类可以内联序列化.参考
其他UnityEngine.Objects
被序列化为实际引用,并且对于
这些,多态性确实有效.你会做一个
ScriptableObject
派生类或另一个MonoBehaviour
派生类,
并参考.缺点是您需要存储
Monobehaviour
或scriptable
在某个地方存在对象,并且您不能
有效地内联序列化它.
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屋!