每当我尝试设置继承层次结构时,我发现自己一遍又一遍地陷入这种情况。
在当前的形式中,我有一个代表游戏中所有 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/