[英]Can't cast derived type to base abstract class with type parameter
我有一個簡單的工廠方法,它提供了一個基於提供的泛型類型參數的具體實現實例。 如果具體類繼承自具有類型參數的公共抽象基類,則無法強制轉換它們。 編譯器告訴我Error 2 Cannot convert type 'Car' to 'VehicleBase<T>'
。 如果我用抽象類替換具有相同類型參數的接口,或者如果我從抽象類中刪除泛型類型參數,它工作正常。
interface IWheel
{
}
class CarWheel : IWheel
{
}
abstract class VehicleBase<T>
{
}
class Car : VehicleBase<CarWheel>
{
}
class VehicleFactory
{
public static VehicleBase<T> GetNew<T>()
{
if (typeof(T) == typeof(CarWheel))
{
return (VehicleBase<T>)new Car();
}
else
{
throw new NotSupportedException();
}
}
}
這無法在(VehicleBase<T>)new Car()
上編譯。 這是一個編譯器缺陷,或者這是一個故意的設計決策,以不同的方式處理抽象類和接口與類型參數?
作為一種解決方法,我總是可以使抽象類實現一個接口並將其用作我的工廠方法的返回值,但我仍然想知道為什么會發生這種行為。
這是不可證明的 ,因為通用代碼需要為每個可能的T
工作(使用相同的IL),並且沒有什么可以說Car : VehicleBase<float>
,例如。 編譯器不會過度分析的事實, if
檢查母豬那T
是CarWheel
-靜態檢測器將每個報表中單獨 ,它不會試着去了解情況的原因和影響。
要強迫它,在中間投射到object
:
return (VehicleBase<T>)(object)new Car();
然而! 你的方法並不是真正的“通用”。
這既不是編譯器缺陷也不是故意的決定。 泛型類的類型參數既不是協變的也不是逆變的 ,即同一泛型類的特化之間沒有繼承關系。 來自文檔:
在.NET Framework版本4中,變體類型參數僅限於通用接口和通用委托類型。
這意味着以下代碼將被編譯,因為它使用接口而不是抽象類:
interface IWheel
{
}
class CarWheel : IWheel
{
}
interface IVehicleBase<T>
{
}
class Car : IVehicleBase<CarWheel>
{
}
class VehicleFactory
{
public static IVehicleBase<T> GetNew<T>()
{
if (typeof(T) == typeof(CarWheel))
{
return (IVehicleBase<T>)new Car();
}
else
{
throw new NotSupportedException();
}
}
}
有關更多信息和示例,請查看“ 泛型中的協方差和逆變 ”。
在C#FAQ博客中還有一個Covariance和Contravariance FAQ ,有更多信息,還有一個由11部分組成的系列! 關於Eric Lippert的主題
這似乎有效:
return new Car() as VehicleBase<T>;
我猜是為什么這樣:
由於VehicleBase<T>
泛型類型實例不相關,因此無法證明將它們轉換為可行:
如果T
是Blah
類型,則演員不會工作。 你不能回到對象然后拿另一個分支(畢竟在C#中沒有多重繼承)。
通過將其轉換回object
之前,您再次打開了強制轉換可能會起作用的可能性,因為可能仍然存在一個向下到VehicleBase<CarWheel>
的路徑。 當然,界面可以出現在object
下面的這個樹中的任何地方 ,所以它也應該可以工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.