C#中继承属性类的面向对象建议

3

我希望您能提供一些关于面向对象(OO)的正确建议。

从继承类中访问属性数据的正确方式是什么?

假设有3个类:

public abstract class Vehicle
{
  public int Id {get; set; }    
  public int Wheels {get; set; }
  public string Name {get; set; }
  public string Color {get; set; }
 }
 public class Car : Vehicle
 {
 }
 public class Truck : Vehicle
 {
  public int LoadCapacity {get; set; }  
 }

我的第一个想法是创建一个存储库,可以提供我所寻找的任何属性。

据我看来,需要以下两种类型的查询:

  1. 返回具有特定ID的车辆的属性
  2. 给我所有特定类型的车辆

因此:

public class VehicleRepository
{
    ICollection <???> _vehicles;

    ??? GetVehicle(int Id);
    ??? GetVehicles(??? vehicleType);
}

这些???是我不确定的内容。

我的想法是为IVehicle添加一个接口,并使用它来实现Vehicle。 结果可能如下所示:

public class VehicleRepository
{
    ICollection <IVehicle> _vehicles;

    IVehicle GetVehicle(int Id);
    ICollection <IVehicle> GetVehicles(IVehicle vehicleType);
}

这显然不起作用。
public IVehicle GetVehicle(int Id)
{
    return _vehicles.First(x=>x.Id == Id);
    // The above want compile as the interface has no attributes
}

如果我使用Vehicle而不是IVehicle,'First(x=>x.Id == Id)'将正常工作,但如果车辆是卡车,则不会返回“LoadCapacity”。

查看GetVehicles函数时,我考虑的是:

public ICollection <T> GetVehicles <T> ()
{
    var vehicles = _vehicles.Where(???);
    return vehicles;
}

我有点不确定那里应该填什么,但是我想避免使用反射,只是读取程序集和类类型等。

谢谢你的建议。


1
你所说的“attribute”是指“属性”吗?属性就像[Obsolete][Serializable]这样的东西。 - Eric Lippert
抱歉,我是指属性,在这种情况下:Id、Wheels、Name、Color等。 - Mike Bryant
2个回答

3
为了存储和获取车辆信息,您需要做的只是像这样操作:
class VehicleRepository {
    List<Vehicle> vehicles;
}

要检索它们,只需使用 IEnumerable<T>.OfType<U>()

VehicleRepository repository = ...
repository.vehicles.OfType<Car>(); // This will get you all of the cars
repository.vehicles.OfType<Truck>(); // This will get you all of the trucks

如果你想让它更加精致,你可以将VehicleRepository变成自己的一个集合,通过让它实现IEnumerable<T>接口。考虑以下代码:
class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public IEnumerator<Vehicle> GetEnumerator() {
        return vehicles.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return this.GetEnumerator();
    }
}

然后,您可以直接对集合进行查询,如下所示:

public static void Main() {
    VehicleRepository repository = ...;

    // Notice that we skip accessing the vehicles member
    // because by implementing IEnumerable<T> this class
    // becomes a collection. Now you can use OfType<T> directly.
    repository.OfType<Car>(); 
}

编辑:如果要执行类似GetVehicleByID这样的操作,您可以尝试以下方法:

class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public Vehicle GetVehicleByID(Int32 id) {
        return vehicles[id];
    }
}

你也可以使用一个索引器,像这样:

class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public Vehicle this[Int32 id] {
        get { return vehicles[id]; }
    }
}

为了从卡车中获取LoadCapacity,你只需要像这样做:
public static void Main() {
   VehicleRepository repository = ...

   // Assuming index zero is a truck
   Truck truck = (Truck)repository.GetVehicleByID(0);
   truck.LoadCapacity = ...
}

一种欺骗性的方法,可以获取特定类型的所有项目(当绑定到UI时,即假设您正在使用Strings),而不使用反射是匹配类型名称的ToString值。例如:

public static void Main() {
   VehicleRepository repository = ...

   // Assume we're storing off the typename in the UI dropdown.
   // so that when the user selects it, we automatically have the correct
   // type name we want to filter by.
   String truckTypeName = typeof(Truck).GetType().ToString();      

   // Filter only by those types with a matching type name. Inefficient,
   // but it does avoid reflection.
   repository.Where(vehicle => vehicle.GetType().ToString() == truckTypeName)
}

两个问题:1)有没有一种方法在运行时通过类型名称访问车辆类型。我考虑使用下拉框显示所有车辆类型,选择后触发该方法。另外,您对GetVehicle(Id)方法有什么想法,它将返回一个车辆而不是具体类的实例。如果我在运行时进行此选择,如何获取类值? - Mike Bryant
发布了一些更新的技巧,你可能会用到。UI方面如果没有更多具体信息会有点困难,但我确实发布了一个解决方案(虽然不是很好)。 - sircodesalot
Getby ID的功能很好,谢谢。 UI这个是我之前想的方法,只是希望能避免使用GetType().ToString()。这是一种相当古老的方式,但如果它能工作的话,我会继续使用它。 - Mike Bryant
肯定有更好的方法,那只是一种通用的方法。但是,您可以考虑打开另一个带有更多详细信息的问题。 - sircodesalot

0

您可以使用 OfType 方法获取特定类型的集合中的项目:

public ICollection<T> GetVehicles<T>() {
  return _vehicles.OfType<T>();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接