如何通过父类可以访问仅由某些子类实现的属性?

时间:2013-06-20 05:50:34

标签: c# class abstract-class

假设我有以下代码:

public abstract class Vehicle
{    
  public Transmission MyTransmission;
  public int NumberOfWheels;
  public int NumberOfSeats;
  public int Weight;
  public int TopSpeed; //etc.
}

public class Car : Vehicle
{
  public int SteeringWheelSize = 10;
}

public class Truck : Vehicle
{
  public int SteeringWheelSize = 20;
}

public class Bike : Vehicle
{

}

public class FourWheelTransmission
{
  public Vehicle ParentVehicle;
  public Transmission(Vehicle vehicle)
  {
    ParentVehicle = vehicle;
    //here, I want to access the SteeringWheelSize from its ParentVehicle object.
  }
}

要完成上一条评论中的目标,最佳方法应该是什么?当然,一种方法是制作两个抽象类:“公共抽象类TwoWheelVehicle”和“公共抽象类FourWheelVehicle”,但是如果我们不想重复FourwheelVehicle和TwoWheelVehicle中常见的所有类似属性,那么有什么允许FourWheelTransmission类访问其车辆的SteeringWheelSize的其他方式?

4 个答案:

答案 0 :(得分:3)

怎么样:

public abstract class Vehicle
{    
  public Transmission MyTransmission;
  public int NumberOfWheels;
  public int NumberOfSeats;
  public int Weight;
  public int TopSpeed; //etc.
}

public abstract class FourWheelVehicle : Vehicle
{
  public int SteeringWheelSize;
}

public class Car : FourWheelVehicle
{
    public Car()
    {
        SteeringWheelSize = 10;
    }
}

public class Truck : FourWheelVehicle
{
    public Truck()
    {
        SteeringWheelSize = 20;
    }
}


public class FourWheelTransmission
{
  public FourWheelVehicle ParentVehicle;
  public Transmission(FourWheelVehicle vehicle)
  {
    ParentVehicle = vehicle;
    //here, I want to access the SteeringWheelSize from its ParentVehicle object.
  }
}

答案 1 :(得分:2)

图片中没有Bike,我觉得Vehicle应该有一个SteeringWheelSize,在构造函数中赋值,由子类调用。

public abstract class Vehicle
{
    public int SteeringWheelSize { get; private set; }
    ...

    protected Vehicle(int steeringWheelSize)
    {
        SteeringWheelSize = steeringWheelSize;
    }
}

public class Car : Vehicle
{
    public Car() : base(20)
    {
    }
}

...

但是,您现在遇到问题:Bike没有方向盘,因此您的模型不再合适。如果您希望能够对BikeCar进行建模,则可能需要在VehicleCar之间设置另一个类,并将SteeringWheelSize成员放入相反 - 然后FourWheelTransmission将被传递。 (这实际上是MarcinJuraszek的答案,虽然我会给新的中间类一个接受上述方向盘尺寸的构造函数。)

然后在使用一次继承的方面略显尴尬 - 你有效地决定“它是否有方向盘”是一个重要的区别;你不能以同样的方式在其他地方做出不同的区别,因为在C#中缺乏多个实现继承。

或者,CarTruck都可以实现接口,表示他们有方向盘,FourWheelTransmission可以使用它。那时你可以仍然使用中间抽象类,但你不必:

public interface ISteerable
{
    int SteeringWheelSize { get; }
}

public abstract class Vehicle
{
    // Properties here
}

public class Car : Vehicle, ISteerable
{
    public SteeringWheelSize { get { return 20; } }
}

...

public class FourWheelTransmission
{
    // We know we can safely cast this to ISteerable
    private Vehicle vehicle;

    private FourWheelTransmission(Vehicle vehicle)
    {
        this.vehicle = vehicle;
    }

    public static FourWheelTransmission<T> FromSteerableVehicle(T vehicle)
        where T : Vehicle, ISteerable
    {
    }
}

请注意这里的轻微尴尬 - 我们无法向编译器表达FourWheelTransmission将有一个变量,它既是Vehicle 的子类,又是的实现ISteerable,除非我们将FourWheelTransmission本身设为通用且使用约束。我上面有一个解决方法,你只能构建基于这种类型的FourWheelTransmission实例,但没有FourWheelTransmission是通用的。如果Vehicle是一个界面,那么ISteerable可以扩展IVehicle

另请注意,此要求使用属性而不是公共字段 - 接口无法指定字段。无论如何,我认为这是一件好事 - 我非常不喜欢公共领域,因为他们通过公共API公开实现细节

答案 2 :(得分:0)

一个简单的解决方案是:

你也可以给两个轮车转向尺寸一个默认值(比如-1),并使用逻辑中的条件,无论转向尺寸在哪里使用。

答案 3 :(得分:0)

我会创建一个界面。

public abstract class Vehicle {    
  public Transmission MyTransmission  { get; set; }
  public int NumberOfWheels { get; set; }
  public int NumberOfSeats { get; set; }
  public int Weight { get; set; }
  public int TopSpeed { get; set; } //etc.
}

public interface ISteeringWheelVehicle {
    int SteeringWheelSize { get; set; }
}

public class Car : Vehicle, ISteeringWheelVehicle {
    public Car() {
        SteeringWheelSize = 10;
    }

    public int SteeringWheelSize { get; set; }
}

public class Truck : Vehicle, ISteeringWheelVehicle {
    public Truck() {
        SteeringWheelSize = 20;
    }

    public int SteeringWheelSize { get; set; }
}

public class Bike : Vehicle {
}

public class FourWheelTransmission {
    public Vehicle ParentVehicle;
    public Transmission(Vehicle vehicle) {
        ParentVehicle = vehicle;

        if (ParentVehicle is ISteeringWheelVehicle) {
            var steeringWheelSize = ((ISteeringWheelVehicle)ParentVehicle).SteeringWheelSize;
        }
    }
}