c# - 不能使用二级派生类作为通用基类类型的参数

标签 c# generics inheritance

我有一个有趣的情况,其中某些事情正在工作,但其他事情却没有,我不确定为什么。下面是近似于我的情况的代码。我在存储库中有一个静态的,它采用由基本类型的对象实现的通用类型。然后我有两个级别的基于该通用类型的派生类。第一级派生类填充了基类型的通用参数并且工作正常,但是任何从填充了通用参数的类派生的类都不能代替它派生的基类工作。

public class Vehicle<TVehicleType, TStorage>
{
}

public class Car : Vehicle<Car, ParkingLot>
{
}

public class PickupTruck : Car
{
}

public class Dealership <TDrivableVehicle>
{
    public static TDrivableVehicle GetVehicle<TVehicleType, TStorage>(TStorage lot)
         where TDrivableVehicle : Vehicle<TVehicleType, TStorage>, new()
    {
    }
}

public class CarDealership : Dealership<Car>
{
    public static Car GetDrivableVehicle(aCarParkingLot)
    {
        return Dealership.GetDrivableVehicle<Car, CarParkingLot>(aCarParkingLot); <-- Works fine
    }
}

public class PickupTruckDealership : CarDealership
{
    public static PickupTruck GetDrivableVehicle(aCarParkingLot)
    {
        return Dealership.GetDrivableVehicle<PickupTruck, CarParkingLot>(aCarParkingLot); <-- fails
    }
}

就 PickupTruck 理解其通用基础而言,某些方面似乎可以正常工作,但扩展(此处未显示)和将类型传递给类型参数(特别是 GetDrivableVehicle 调用)并非如此。我的猜测是扩展方法与类型参数问题有关,因为它需要弄清楚类型。

有什么想法为什么这不起作用和/或可以采取什么措施来解决它?

最佳答案

将您的代码重写到可以使它在您所说的地方失败的程度 - 问题正如 Thom Smith 所说:PickupTruck继承Car因此是 Vehicle<Car, ParkingLot> , 不是 Vehicle<PickupTruck, ParkingLot> .此外,由于它是通用继承,因此它不可能是除此之外的任何其他内容。

我知道您的代码只是您遇到的问题的简化表示 - 但如果它足够接近,那么我们可以在这里对整体架构进行一些有用的观察。

我不反对泛型基础知道它们的派生对应物——事实上它对工厂特别有用;然而,它几乎总是立即排除任何进一步的继承。

您试图在类型级别编码太多信息;除了我们在这里看到的尖括号的数量之外,Vehicle<TVehicleType, TStorage> 稍微不协调的性质实际上暗示了它。正在确定可以存储它的存储类型。

对我来说,这没有任何意义,因为假设我们有一个 ParkingLot今天,但明天我们也会得到一个Hangar (对于在掩护下存放的汽车)——这将需要一整套全新的车辆类型,由于我们还将派生类型传递给基础 Vehicle<TDerived, ...>,这些车辆类型是不相等的。 - 因此 ParkingLotCarHangarCar 永远不会是等价的,即使两个实例都代表相同的品牌/型号等。

因此,预料到这一点,您已经获得了共同的继承权 Car , 但当然在这一点上任何继承都是毫无意义的因为 CarVehicle<Car,...>所以从它衍生出来的任何东西也必须是。只有多重继承可能不是这种情况,但即使如此,它也无法绕过整个ParkingLot。问题。

问问自己为什么 Vehicle<,>需要了解派生类型?这样你就可以拥有一个工厂方法了吗?在这种情况下,您应该将其放入 Dealership ,或 ParkingLot类型;不是车辆基地:

public interface IVehicle {}
public interface ICar : IVehicle {} //because pickup trucks share some car traits
public interface IPickup : ICar, IVehicle {}
public interface IStorage {}

public class Car : ICar, IVehicle {}
public class Pickup : IPickup, ICar, IVehicle {}

public class ParkingLot : IStorage {}
public class Hangar : IStorage {}

public class Dealership
{
  public static TVehicle GetVehicle<TVehicle>(IStorage storage)
    where TVehicle : IVehicle, new()
  {

  }
}

//now you can specialise if you really need to

public class CarDealership
{
    public static Car GetVehicle(IStorage storage)
    {
        return Dealership.GetVehicle<Car>(storage);
    }
}

public class PickupDealership
{
    public static Pickup GetVehicle(IStorage storage)
    {
        return Dealership.GetVehicle<Pickup>(storage);
    }
}

现在您有了车辆类型之间的运行时关系;允许不同的具体类型共享特征,例如 ICar 上的特征或 IPickup接口(interface);但是你已经打破了车辆和它的存储之间的关系所以你可以获得一个IVehicle来自FootballPitch或者把它从码头开到 RiverBed如果需要的话。

关于c# - 不能使用二级派生类作为通用基类类型的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12198649/

相关文章:

c# - 从范围引用了类型为 'x' 的变量 'Product',但未定义

c# - C#检测黑白图像中的多边形点

spring-mvc - 如何将通用集合类对象作为参数传递

c# - 为什么 IEnumerable<T> 不实现 Add(T)?

c++ - 无法将父类(super class)转换为子类

c# - 编译错误 :A field initializer cannot reference the non-static field, 方法或属性

c# - 阻止 Visual Studio 在 switch-case 语句中添加换行符

java - 在 Java 中遍历通用 Trie

java - 继承层次结构改变以减少代码重复

python - 在继承的数据类中使用 __new__