[英]Override base class property to a derived type and access via base class
想象以下几类:
public abstract class State {}
public abstract class View : MonoBehaviour {
public State state;
}
现在,我想从这两个类派生来创建StateA
和ItemA
。
public class StateA { // some properties }
public class ViewA : View {
public StateA state;
}
ViewA
应该只接受StateA
作为其状态。 设置假设的StateB
应该是不可能的。 当我尝试设置ViewA
的状态时
View view = someGameObject.GetComponent<View>;
view.state = new StateA ();
只设置基类的状态。 在我的情况下,实际上无法ViewA
转换为ViewA
,因为必须动态地ViewA
。
现在我想出了两种可能的解决方案。
解决方案1-类型检查并强制转换
所有状态类保持不变。 基类正在检查状态的正确类型。
public abstract class View : MonoBehaviour {
public State state;
public Type stateType;
public void SetState (State state) {
if (state.GetType () == this.stateType) {
this.state = state;
}
}
}
要访问ViewA
的状态, ViewA
执行以下操作:
(StateA)this.state
解决方案2-统一方式
State
将更改为从MonoBehaviour派生。
public abstract class State : MonoBehaviour {}
要向项目添加状态,我只需向游戏对象添加一个新的StateA
组件。 该项目然后使用GetComponent加载该状态以访问它。
viewA.gameObject.AddComponent<StateA> (); // set state with fixed type
viewA.gameObject.AddComponent (type); // set state dynamically
this.gameObject.GetComponent<StateA> (); // get state in item class
结论
我认为这两种解决方案都不理想。 你们知道做这种事情的更好方法吗? 希望您了解我正在努力实现的目标。 期待看到您的想法。
编辑
似乎我简化了我的问题。 为了弄清楚为什么要这样做,我将Item
视为UI中的“ View
。 StateA
没有任何功能。 取而代之的是让视图知道它应该做什么的一些属性。 例如,对于表视图,状态将包含要显示的事物的集合。
public class StateA : State {
SomeObject[] tableViewData; // which data to load into the table view
}
或换另一种观点。
public class StateB : State {
bool hideButtonXY; //should I hide that button?
}
在另一堂课中,我保留了上一次显示的视图及其各自状态的历史记录。 这样,我可以通过普通的Web浏览器实现来回功能。 我希望这可以使我的意图明确。
这是一个相当普遍的问题,是由于在Unity中需要使用MonoBehaviours的奇怪方式和对继承的普遍误用所造成的。 这不是您可以解决的事情,而是您为了避免而设计的事情。
这一切都取决于您为什么需要State的子类,但是我假设它是类似的:base State具有一些基本逻辑,而派生的StateA具有一些新的/修改的属性/逻辑。 假设这是真的:
用代码写出的示例:
abstract class State {
public int sharedField;
public sealed void DoThing() {
sharedField = 1;
DoThingInternal();
}
protected abstract void DoThingInternal();
}
abstract class Item {
State state;
public abstract void TestMethod();
}
class StateA : State {
public int customField = 10;
protected override void DoThingInternal() {
sharedField = 10;
}
}
class ItemA : Item {
public ItemA() {
//read from somewhere else, pass it in, etc.
state = new StateA();
}
public override void TestMethod() {
state.DoThing();
Console.WriteLine(state.sharedField); //will print 10
}
}
这是一种非常常见的模式,尤其是在Unity中,当您想要使用继承时。 这种模式在Unity之外也可以很好地工作,并且避免使用泛型,因此一般而言很有用。
注意: public方法上的密封属性的要点是防止其他人/您自己稍后再尝试隐藏它(public new void DoThing()或只是public void DoThing()),然后在不起作用时感到困惑。
如果要覆盖它,则因为是通过基类调用它的,所以它将调用该函数的基版本,而不是新方法。 将其定义为抽象/虚拟并由基类本身调用即可解决此问题。 这确实意味着您已经有效地定义了:
interface IState {
public int sharedField;
public void DoThing();
}
因此,您可能会看到通过界面并注意实现可以达到相同的结果。
编辑以使示例符合问题:
abstract class State {
public sealed Button[] GetHiddenButtons() {
GetHiddenButtonsInternal();
}
public sealed object[] GetObjects() {
GetObjectsInternal();
}
protected abstract Button[] GetHiddenButtonsInternal();
protected abstract object[] GetObjects();
}
abstract class Item {
State state;
public abstract void Render();
}
class StateA : State {
public Button[] _hiddenButtons;
public object[] _objects;
public StateA()
{
//get hidden buttons from somewhere/pass them in/create them.
_hiddenButtons = new Button[0];
//get objects from somewhere/pass them in/create them.
_objects = new object[0];
}
protected override Button[] GetHiddenButtons() {
return _hiddenButtons;
}
protected override object[] GetObjects() {
return _objects;
}
}
class ItemA : Item {
public ItemA() {
//read from somewhere else, pass it in, etc.
state = new StateA();
}
public override void Render() {
//get objects
var objects = state.GetObjects(); //returns array from StateA
//get hidden buttons to hide
var hiddenButtons = state.GetHiddenButtons();
}
}
基本上,您正在做的是创建一个通用的接口 ,以服务您需要执行的任何状态。 该模式并没有说明您需要如何返回它们,因此您的GetHiddenButtons()方法可以:返回ID列表,返回对象,与GameObject联系以获取列表,返回硬编码列表等。
这种模式使您可以完全按照自己的意愿去做,只需要确保基本状态的通用性足以允许您去做即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.