失去了继承和多态性

时间:2015-10-31 15:07:05

标签: c# inheritance casting polymorphism

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

示例与Car and Engine和Driver等书籍中的几乎所有常见基类相同: 当我添加从基类继承的特殊类,如Racecar:Car和TurboEngine:Engine并将属性添加到专用类,如boost to TurboEngine,我会遇到同样的问题,当我想使用基本的代码和方法时几乎没有覆盖几乎所有方法的类。

我已经将我的字段重构为属性,并尝试使用newoverride,但逻辑问题保持不变。

如果代码太多,我可以尝试将其缩短到我遇到的单个问题。

检查代码显示了问题。上/下铸造没有帮助。我认为这更像是一个基本的思维错误,因为OOP编程很难为一个旧的汇编人学习。

EDIT ----更新:

好吧,按照设计。 https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) 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;
   }
}

2 个答案:

答案 0 :(得分:7)

  

示例与CarEngine等书籍中的几乎所有常见基类相同...当我添加从Racecar : Car和{{TurboEngine : Engine等基类继承的特殊类时1}}并将属性添加到专用类,如boost TurboEngine我会遇到同样的问题,当我想使用基类中的代码和方法时,不会覆盖几乎所有的方法。

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

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

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

答案 1 :(得分:1)

您不能从基类转换为派生类,只能反过来。您将不得不创建一个TetrisField而不是基础GameField。

GameField2D fGame = new TetrisField2D(10,10);

不幸的是C# does not support property covariance(我真的希望它发生在我之前发生的事情。),所以为了解决使用不同类型的Field的问题,你需要使用new TetrisField类中的关键字。但是,非常重要的是,您只能在转换为TetrisField时修改字段,否则您实际上将修改基类的字段。