c# - 在 Unity 中使用 GetComponent 时通过基类管理派生类?

标签 c# inheritance unity3d casting

每当我尝试设置继承层次结构时,我发现自己一遍又一遍地陷入这种情况。

在当前的形式中,我有一个代表游戏中所有 UI 元素的基类。我称这个类为 UI_Toggleable。此类具有每个派生类都可以设置的枚举属性。以下是代码的简要介绍:

public class UI_Toggleable 
{

    // The Menu Type enum that all derived classes must define.
    protected UIMenus menuType;

    // Gives any child of this class a toggle function
    // to enable/disable UI when needed.
    public void ToggleUI()
    {
        // Toggle Code
    }

    // Public property Getter - Read Only Access.
    // Only derived classes can define the value of the menu type.
    public virtual UIMenus MenuType
    {
        get { return menuType; }
    }
}

现在,假设一个名为 InventoryUI 的类派生自 Toggleable,我们有以下内容。

 public class  InventoryUI : UI_Toggleable
{

    private void Awake()
    {
        _instance = this;
        menuType = UIMenus.Inventory;
    }

    public override UIMenus MenuType
    {
        get { return menuType; }
    }
}

现在,如果我尝试为这些对象实现一个管理器,我将想要获取每个派生类的菜单类型。但是,我不想假设 UI_Toggleable 类的类型。相反,我想要做的是获取任何派生类作为 UI_Toggleable,然后继续调用 MenuType 方法以获取其类型。

UI_Toggleable toggleable = GetComponent<UI_Toggleable>();
toggleable.MenuType;

上面的问题是,它会返回基类的 MenuType,而不是我作为基类检索的派生类。这在某种程度上是意料之中的,但我想在不执行以下操作的情况下获取派生类的 MenuType:

if(GetComponent<UI_Toggleable>() is  InventoryUI )
 InventoryUI toggleable = GetComponent< InventoryUI >();
toggleable.MenuType;

上面的方法可行,但它违背了我设置一个与子类共享相似属性的基类的目的。进行所有这些转换和检查只会让代码看起来难以阅读和解耦。

我尝试过的其他事情包括:

  • 创建一个定义函数 GetMenuType 的接口(interface) IMenuType。每个派生类都实现了该方法,在我的管理器中,我会检查 if(toggleable is IMenuType)。如果为真,则尝试调用 ((IMenuType)toggleable).GetMenuType。
  • 让 MenuType 属性 getter 成为每个派生类都必须实现的抽象函数。但与上述情况类似,在尝试调用该方法之前,我仍然必须进行转换检查。
  • 虽然不是我的优先事项,但 MenuType 方法并不意味着是虚拟的。

最佳答案

您没有正确设置基类的 menuType。不要在派生类的 Awake 方法中设置它,而是在构造函数中设置它,如下所示:

public class UI_Toggleable {
    public UIMenus MenuType {get;}
    // Subclasses must pass the correct menuType here
    protected UI_Toggleable(UIMenus menuType) {
        MenuType = menuType;
    }
}
public class  InventoryUI : UI_Toggleable {
    // Pass the proper menu type for storing inside the base class
    public InventoryUI() : base(UIMenus.Inventory) {
    }
}

请注意 MenuType 现在是基类的只读属性,而不是具有覆盖的虚拟属性。

I cannot really use the constructor. Is it acceptable if I set it in the Awake method instead?

从您的代码示例中可以看出,Awake 没有及时被调用,以便基类提供正确的值。在这种情况下,您使用一个 abstract getter-only 属性,如下所示:

public class UI_Toggleable {
    public abstract UIMenus MenuType {get;}
}
public class  InventoryUI : UI_Toggleable {
    public override UIMenus MenuType {
        get => UIMenus.Inventory
    }
}

注意get => UIMenus.Inventory 的旧语法是 get { return UIMenus.Inventory; }

关于c# - 在 Unity 中使用 GetComponent 时通过基类管理派生类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46567872/

相关文章:

javascript - ASP.NET Core 3.0 MVC 连接中的 SignalR 保持事件状态不起作用?

c# - 组合而不是继承

javascript - 防止构造函数的多个实例共享相同的原型(prototype)属性

c# - 将对象添加到 Array Unity3d C# 的奇怪行为

c# - Linq 中的 IF else 语句

c# - 将 C# 应用程序与现有网站集成

c# - 如何在网格的行和列中进行绑定(bind)?

inheritance - Fortran 预处理器指令用法

c# - 运行所有 Start 方法后创建事件链

android - Unity facebook sdk 'Didn' t find class "com.facebook.FacebookContentProvider"'对此还有什么建议吗?