我有一个有趣的情况,某些事情正在发挥,但其他事情没有,我不知道为什么。下面是与我的情况相近的代码。我在存储库中有一个静态,它采用由基类对象实现的泛型类型。然后,我基于该泛型类型有两个级别的派生类。派生类的第一级填充基类型的泛型参数并且工作正常,但是从填充泛型参数的类派生的任何类都不能替代它派生自的基类。
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调用)。我的猜测是扩展方法与类型参数问题有关,因为它需要弄清楚类型。
任何想法为什么这不起作用和/或可以做些什么来解决它?
答案 0 :(得分:2)
将代码重写到可以让它失败的地方 - 问题就像Thom Smith说的那样:PickupTruck
继承Car
因此是{{1 },而不是Vehicle<Car, ParkingLot>
。此外,由于它的通用继承,它不可能是除此之外的任何其他东西。
我知道你的代码只是你所遇问题的简要表示 - 但如果它足够接近,那么我们可以在这里就整体架构做一些有用的观察。
我并不反对通用基地了解他们派生的同行 - 事实上它对工厂特别有用;但它几乎总是立即排除任何进一步的继承。
您尝试在类型级别编码太多信息;除了我们在这里看到的尖括号的数量之外,它实际上暗示了Vehicle<PickupTruck, ParkingLot>
确定它可以存储在其中的存储类型的略微不协调的性质。
对我来说,这没有任何意义,因为我们今天有一个Vehicle<TVehicleType, TStorage>
,但明天我们也得到一个ParkingLot
(对于汽车存放在掩护下) - 这将需要由于我们也将派生类型传递到基础Hangar
- ergo Vehicle<TDerived, ...>
和ParkingLotCar
可以从不通过车辆类型的全新类型是等效的,即使两个实例都代表相同的品牌/模型等。
所以,在预期的情况下,你已经去了一个共同HangarCar
的继承,但当然在那时任何继承都没有意义,因为Car
是一个Car
所以任何派生的从它也必须。只有多重继承可能不是这种情况,但即便如此,它也无法解决整个Vehicle<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
获得IVehicle
,或者如果你需要,可以从码头开出FootballPitch
。
答案 1 :(得分:1)
您设置的方式,PickupTruck
不是Vehicle<PickupTruck, CarParkingLot>
,而只是Vehicle<Car, CarParkingLot>
。这种无限的模板递归可能会让人很困惑。您可以通过声明PickupTruck : Vehicle<PickupTruck, CarParkingLot>
,通过修改co [ntra]方差,或通过重构类层次结构来避免混淆模式来解决此特定问题。
答案 2 :(得分:0)
您正在尝试使用派生类来代替基类。这不行。您应该能够使用BASE类而不是更多派生类,而不是相反。您可以将Car转换为接口(ICar)并让PickupTruck实现ICar。那会有用。
阅读逆变与协方差。 http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx