我有一个RTS游戏对象类WorldObject
。在RTS游戏中,通过鼠标点击发送对对象的各种动作。我发明了以下系统:
每个WorldObject都有一个包含可用操作的Action[]
数组。 Action
构造函数如下所示:
public Action(WorldObject ownerObj) {
owner = ownerObj;
}
在WorldObject
构造函数(实际上是Unity Start()
方法)中,Action
是从对象定义中包含的字符串中实例化的。这非常舒服,因为我可以在Unity UI中编辑动作:
//Load actions
int l = actions_str.Length;
actions = new Action[l];
for (int i = 0; i < l; i++)
{
actions[i] = Action.fromString(actions_str[i], "", this);
if (actions[i] != null)
Debug.Log("Created action...");
else
Debug.LogWarning("Failed to create action!");
}
然后使用Reflection:
从字符串转换动作 public static Action.fromString(string className, WorldObject owner) {
... some code ...
//Get the info about constructor (using array literal)
constructor = t.GetConstructor(new Type[] { typeof(string), typeof(WorldObject) });
... some code ...
}
所有者是一些受保护的变量。默认操作没用,但许多类可以从此继承,如BuildUnit:Action
。如果您创建高级操作,它将只能在某些单元上运行 - 在这种情况下,BuildUnit
需要一个Factory:WorldObject
实例,以便与工厂构建队列一起运行等等。
这意味着我已经在BuildUnit:Action
重载了一个构造函数,需要Factory
:
public BuildUnit(Factory factory) : base(factory)
{
f = factory;
}
但是,当我将BuildUnit
分配给Factory
时,这就是我所犯的错误:
No suitable constructor found for 'Actions.SpawnEgg'.
UnityEngine.Debug:LogError(Object)
Actions.Action:fromString(String, String, WorldObject) (at Assets/WorldObject/Action.cs:66)
Units.WorldObject:Start() (at Assets/WorldObject/WorldObject.cs:349)
Units.Unit:Start() (at Assets/WorldObject/Unit/Unit.cs:38)
似乎传递了WorldObject
实例,而不是Factory
子实例。
我认为这不应该发生。无论如何:
is
其中一个子节点,它仍然只是this
中包含的父实例?假设答案是2.
,我已经找到了一个令人讨厌的解决方法:
//The return value should be castable back to original class (as Factory)
protected virtual WorldObject GetThis() {
return this;
}
答案 0 :(得分:1)
这里有两个不同的问题,一般是您要问的问题,以及您遇到的具体错误。
一般性问题
没有&#34;父实例&#34;或者&#34;子实例&#34;。实例始终是一种特定类型,并且始终可以强制转换为它匹配的任何其他类型。这意味着如果Factory
继承WorldObject
,这将始终有效:
Factory f = new Factory();
WorldObject wo = f; // Works, because Factory is-a WorldObject.
Factory f2 = (Factory)wo; // Works, because the reference wo points to a Factory object.
你的解决方法没有做任何我的第二行不会做的事情=在作业中向上转播是隐含的。
具体问题
您获得的错误是由于Reflection如何搜索类型和方法签名。在第43行的代码中,您有以下这一行:
constructor = t.GetConstructor(new Type[] { typeof(string), typeof(WorldObject) });
它正在做的是搜索带有WorldObject
的操作的构造函数。但是,您的操作的构造函数需要Factory
,而不是WorldObject
。这在使用反射时会有所不同。
确实,在调用构造函数时,编译器知道Factory
是一个WorldObject
并且可以匹配它,但是当使用反射时,采用Factory
的构造函数和采用WorldObject
的构造函数之间存在差异。你可以拥有两者,并且它们的行为有点不同,你必须明确如何调用它。
换句话说,如果你想要一个基于泛型反射的方法来实例化你的类型,你需要让它们都支持相同的构造函数(在这种情况下,一个WorldObject
ctor),或者你的反思代码更聪明(和更丑陋),遍历所有构造函数并查找参数类型为WorldObject
后代的构造函数。