我可以从 C# 中的“this”获取子类实例吗?

本文关键字:子类 获取 实例 this 中的 我可以 | 更新日期: 2023-09-27 18:30:17

我有一个RTS游戏对象类WorldObject。在RTS游戏中,通过鼠标点击来调度对象上的各种操作。我发明了以下系统:

每个 WorldObject 都有一个包含可用操作的Action[]数组。 Action构造函数如下所示:

public Action(WorldObject ownerObj) {
    owner = ownerObj;
}

在构造函数(实际上是 Unity Start()方法)WorldObject中,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!");
        }

然后使用反射从字符串转换操作:

    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. 如果是这样,我应该怎么做才能保持这个概念的运作?

假设答案是2.,我已经想出了一个令人厌恶的解决方法:

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

我可以从 C# 中的“this”获取子类实例吗?

这里有两个不同的问题,您询问的一般问题和您遇到的特定错误。

一般问题

没有"父实例"或"子实例"这样的东西。实例始终属于一种特定类型,并且始终可以强制转换为它匹配的任何其他类型。这意味着如果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.

您的解决方法不会执行我的第二行不会执行的操作 = 作业中的向上转换是隐式的。

具体问题

您收到的错误是由于反射搜索类型和方法签名的方式。在您的代码中,在第 43 行中,您有以下行:

constructor = t.GetConstructor(new Type[] { typeof(string), typeof(WorldObject) });

它正在做的是在采取WorldObject的操作上搜索构造函数。但是,您的操作具有一个构造函数,该构造函数采用Factory,而不是WorldObject。这在使用反射时会有所不同。

的确,在调用构造函数时,编译器知道FactoryWorldObject并且可以匹配它,但是在使用反射时,需要Factory的构造函数和需要WorldObject的构造函数之间存在差异。你可以同时拥有两者,它们的行为略有不同,你必须明确如何称呼它。

换句话说,如果你想要一个通用的基于反射的方法来实例化你的类型,你要么需要让它们都支持相同的构造函数(在本例中,一个WorldObject ctor),要么让你的反射代码更聪明(和更丑陋),迭代所有构造函数并查找参数类型是WorldObject后代的构造函数。