假设我有以下代码:
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的其他方式?
答案 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
没有方向盘,因此您的模型不再合适。如果您希望能够对Bike
和Car
进行建模,则可能需要在Vehicle
和Car
之间设置另一个类,并将SteeringWheelSize
成员放入相反 - 然后FourWheelTransmission
将被传递。 (这实际上是MarcinJuraszek的答案,虽然我会给新的中间类一个接受上述方向盘尺寸的构造函数。)
然后在使用一次继承的方面略显尴尬 - 你有效地决定“它是否有方向盘”是一个重要的区别;你不能以同样的方式在其他地方做出不同的区别,因为在C#中缺乏多个实现继承。
或者,Car
和Truck
都可以实现接口,表示他们有方向盘,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;
}
}
}