[英]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.