How do I need to restructure or refactor my code, so that I can use embedded and inherited objects to work as expected with least code repetition. this code is only an example, I think it is a basic error in my OOP-thinking...
The example would be the same with almost all common base classes in books like Car and Engine and Driver: When I add special classes that inherit from base like Racecar:Car and TurboEngine:Engine and add properties to the specialized class like boost to TurboEngine I would run into the same problem, when I want to use as much as code and methods from the base classes without overriding almost all methods.
I already refactored my fields to properties and tried with new
and override
but the logical problem stays the same.
If that code is too much I can try to shorten it more to the single problem I stuck in.
the examle code shows the problems. up/down casting won't help. I guess it's more a basic thinking error as OOP programming is hard to learn for an old assembler guy.
EDIT----UPDATED:
okay it's by design. https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) https://en.wikipedia.org/wiki/Liskov_substitution_principle
I feel a bit releaved now...stuck there and thought: can't be true. There should be more places to point to, gather and demonstrate these common mistakes depending on the level of experience of developers. Also in many books it is far from highlighted. Now knowing the correct term for it, I find more. But still many deep technical explanations not suitable for the novice. That could save a lot of time :)
var root = new Vector2D(0,0);
GameField2D fGame = new GameField2D(10,10);
fGame.Init();
fGame.Field[1,1].ParentPoint = root;
fGame.Field[1,1].Color = 1; //<--ERROR to be expected
var test = (TetrisField2D)fGame; //<---ERROR cast not possible
TetrisField2D fTetris = new TetrisField2D(10,10);
fTetris.Init();
fTetris.Field[1,1].ParentPoint = root; //<--ERROR Nullreference because only base class field is initiated.
Here are the classes:
the inheriting one:
public class TetrisField2D: GameField2D {
public int Lifes;
public TetrisPoint[,] Field; //I want of course Tetrispoints with color
public TetrisField2D(): base(){}
public TetrisField2D(int x,int y) : base (x,y) {}
}
Base class
public class GameField2D { //"generic"
public GamePoint[,] Field;
private int size;
//CTORs
public GameField2D(){
Field = new GamePoint[9,9];
size = 10;
}
public GameField2D(int x,int y){
Field = new GamePoint[x-1,y-1];
size= x-1;
}
public GameField2D(GamePoint[,] f){
Field = f;
size = f.GetLength(0);
}
public void Init() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
Field[i,j] = new GamePoint();
}
}
}
}
included point classes:
public class TetrisPoint : GamePoint{
public int Color;
public TetrisPoint(){}
public TetrisPoint(int x, int y, int col) : base(x,y) {
Color = col;
}
}
public class GamePoint {
public Vector2D ParentPoint;
public bool Appears;
public int IsUsed;
public GamePoint(){ }
public GamePoint(int x, int y, bool a=false) {
this.ParentPoint = new Vector2D(x,y);
Appears = a;
}
}
public struct Vector2D {
public int X,Y;
public Vector2D(int x,int y) {
this.X=x;
this.Y=y;
}
}