c# - Override base class property to a derived type and access via base class -


imagine following classes:

public abstract class state {}  public abstract class view : monobehaviour {     public state state; } 

now want derive both classes create statea , itema.

public class statea { // properties }  public class viewa : view {     public statea state; } 

viewa should accept statea state. setting hypothetical stateb should not possible. when trying set state of viewa

view view = somegameobject.getcomponent<view>; view.state = new statea (); 

only state of base class set. casting viewa not possible in situation because have cast dynamically.

now came 2 possible solutions.

solution 1 - type check , cast

all state classes remain unchanged. base class checking correct type of state.

public abstract class view : monobehaviour {     public state state;     public type statetype;      public void setstate (state state) {         if (state.gettype () == this.statetype) {             this.state = state;         }     } } 

to access state in viewa this:

(statea)this.state 

solution 2 - unity way

state changed derive monobehaviour.

public abstract class state : monobehaviour {} 

to add state item add new statea component gameobject. item loads state getcomponent access it.

viewa.gameobject.addcomponent<statea> (); // set state fixed type viewa.gameobject.addcomponent (type);     // set state dynamically  this.gameobject.getcomponent<statea> (); // state in item class 

conclusion

both of these solutions not ideal in opinion. guys know of better way kind of stuff? hope understand i'm trying achieve. looking forward see ideas.

edit

seems oversimplified question. make clear why way think of item view in ui. statea not have functionality. instead it's number of properties let view know should do. table view example state contain collection of things show.

public class statea : state {     someobject[] tableviewdata; // data load table view } 

or view.

public class stateb : state {     bool hidebuttonxy; //should hide button? } 

in class keep history of last showed views respective states. way implementing , forth feature normal web browser. hope makes intentions clear.

this common problem caused combination of odd way monobehaviours need used in unity , common misapplication of inheritance. it's not can solve such, it's design in order avoid.

this depends on why need subclasses of state, i'm assuming like: base state has base logic, , derived statea has new/modified properties/logic. assuming true:

  • keep item subclasses using same reference state. because it's subclass, can save property of base type.
  • make standard set of accessors/fields/methods way item subclasses access state subclasses. example: dothing(), processstate(), etc.
  • make these accessors/fields/methods have common code always run, in sealed function.
  • make above methods call internal/protected method defines custom logic need run. these should abstract, or virtual if want provide standard implementation of them.
  • make subclasses override abstract/virtual methods , able access custom code.
  • when call statestoredasbaseclass.dothing(), it'll automatically call statestoredasbaseclass.dothinginternal() overriden in subclass , has custom statea code in it.

example written out in code:

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 somewhere else, pass in, etc.         state = new statea();     }      public override void testmethod() {         state.dothing();         console.writeline(state.sharedfield); //will print 10     } } 

this common pattern, in unity, when want use inheritance this. pattern works outside of unity , avoids generics, useful know in general.

note: point of sealed attribute on public method prevent other people/yourself later trying hide (public new void dothing() or public void dothing()) , being confused when doesn't work.

if override it, because called through base class, it'd call base version of function instead of new method. having defined abstract/virtual , called base class gets around this. mean you've defined:

interface istate {     public int sharedfield;      public void dothing(); } 

so can see same result can achieved interface , paying attention implementation.

edited conform example question:

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 somewhere/pass them in/create them.         _hiddenbuttons = new button[0];          //get objects 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 somewhere else, pass in, etc.         state = new statea();     }      public override void render() {         //get objects         var objects = state.getobjects(); //returns array statea          //get hidden buttons hide         var hiddenbuttons = state.gethiddenbuttons();     } } 

basically, you're doing creating interface generic enough serve whatever need state do. pattern doesn't dictate how need return them, gethiddenbuttons() method could: return list of ids, return objects, contact gameobject list, return hardcoded list, etc.

this pattern allows want do, have make sure base state designed generically enough allow it.


Comments