在遗传和多态性方面丢失

本文关键字:方面丢 多态性 | 更新日期: 2023-09-27 18:20:12

我需要如何重组或重构我的代码,以便使用嵌入和继承的对象以最少的代码重复按预期工作。这段代码只是一个例子,我认为这是我OOP思维中的一个基本错误。。。

这个例子与《汽车与发动机》和《驾驶员》等书中几乎所有常见的基类都是一样的:当我添加从基类继承的特殊类(如Racecar:Car和TurboEngine:Engine),并将属性添加到专门类(如boost到TurboEngine)时,我会遇到同样的问题,当我想在不覆盖几乎所有方法的情况下使用基类中的尽可能多的代码和方法时。

我已经将字段重构为属性,并尝试使用newoverride,但逻辑问题仍然存在。

如果代码太多,我可以试着把它缩短到我遇到的单个问题

examle代码显示了这些问题。向上/向下投射没有帮助。我想这更多的是一个基本的思维错误,因为面向对象编程对于一个老的汇编人员来说很难学习。

编辑----更新:

好吧,这是故意的。https://en.wikipedia.org/wiki/Covariance_and_contravariance_(计算机科学)https://en.wikipedia.org/wiki/Liskov_substitution_principle

我现在觉得有点心软了。。。困在那里想:不可能是真的。根据开发人员的经验水平,应该有更多的地方可以指出、收集和演示这些常见错误。此外,在许多书中,这一点也远未得到强调。现在知道了正确的术语,我发现了更多。但仍有许多深层次的技术解释不适合新手。这可以节省很多时间:)

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.

以下是类别:

继承者:

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) {}
}

基本类

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();
        }
      }
    }
}

包含的点类别:

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;
   }
}

在遗传和多态性方面丢失

这个例子与CarEngine等书中几乎所有常见的基类都是一样的。。。当我添加从基类继承的特殊类(如Racecar : CarTurboEngine : Engine),并将属性添加到专门类(如boost到TurboEngine)时,当我想在不覆盖几乎所有方法的情况下使用基类中的尽可能多的代码和方法时,我会遇到同样的问题。

你遇到的问题是面向对象设计的经典问题。OO可以很好地对派生类更具体但不引入限制的情况进行建模。赛车比汽车更具体,但"赛车只有涡轮发动机"是对汽车发动机种类的限制。

没有明显的方法可以解决这个问题。我在博客上写了一系列文章,更详细地描述了这个问题,以及人们试图解决它的一些方法;你可能会觉得很有趣。

http://ericlippert.com/2015/04/27/wizards-and-warriors-part-one/

不能从基类强制转换为派生类,只能反过来。你必须创建一个TetrisField,而不是基本的GameField。

GameField2D fGame = new TetrisField2D(10,10);

不幸的是,C#不支持属性协方差(我真的希望它能像以前那样支持。),所以为了解决拥有不同类型字段的问题,您需要在TetrisField类中使用new关键字。但是,非常重要的一点是,您只能在转换为TetrisField时修改字段,否则您实际上将修改基类的field。