我可以在C#中从`this`获取子类实例吗?

时间:2014-11-13 11:30:11

标签: c# polymorphism

我有一个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子实例。

我认为这不应该发生。无论如何:

  1. 在父类中,如果它是is其中一个子节点,它仍然只是this中包含的父实例?
  2. 如果是这样,我应该怎样做才能保持这个概念有效?
  3. 假设答案是2.,我已经找到了一个令人讨厌的解决方法:

    //The return value should be castable back to original class (as Factory)
    protected virtual WorldObject GetThis() {
         return this;
    }
    

1 个答案:

答案 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后代的构造函数。