C# Can';t使用类型参数将派生类型强制转换为基抽象类

C# Can';t使用类型参数将派生类型强制转换为基抽象类,c#,compiler-errors,C#,Compiler Errors,我有一个简单的工厂方法,它基于提供的泛型类型参数提供了一个具体的实现实例。如果具体类继承自带有类型参数的公共抽象基类,则我无法强制转换它们。编译器告诉我错误2无法将类型“Car”转换为“VehicleBase”。如果用同一类型参数替换抽象类的接口,或者从抽象类中删除泛型类型参数,则效果很好 interface IWheel { } class CarWheel : IWheel { } abstract class VehicleBase<T> { } class Car :

我有一个简单的工厂方法,它基于提供的泛型类型参数提供了一个具体的实现实例。如果具体类继承自带有类型参数的公共抽象基类,则我无法强制转换它们。编译器告诉我
错误2无法将类型“Car”转换为“VehicleBase”
。如果用同一类型参数替换抽象类的接口,或者从抽象类中删除泛型类型参数,则效果很好

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();
        }
    }
}
接口IWheel
{
}
车轮类别:IWheel
{
}
抽象类车辆数据库
{
}
车辆类别:车辆基地
{
}
等级车辆工厂
{
公共静态车辆数据库GetNew()
{
if(类型(T)=类型(车轮))
{
归还(车辆基地)新车();
}
其他的
{
抛出新的NotSupportedException();
}
}
}
(车辆库)new Car()上编译时失败。
。这是一个编译器缺陷,还是一个故意的设计决策,以不同的方式对待具有类型参数的抽象类和接口


作为一种解决方法,我总是可以让抽象类实现一个接口,并将其用作工厂方法的返回值,但我仍然想知道为什么会发生这种行为。

这是不可证明的,因为泛型代码需要为每个
T
可能的工作(使用相同的IL),例如,没有什么可以说
汽车:汽车基地
。编译器不会过度分析
如果检查
T
CarWheel
,则编译器不会过度分析这一事实-静态检查器会单独处理每条语句,它不会试图理解条件的原因和影响

要强制执行,请将其强制转换为中间的
对象

return (VehicleBase<T>)(object)new Car();
返回(车辆库)(对象)新车();
然而!您的方法本身并不“通用”。

这似乎有效:

return new Car() as VehicleBase<T>;
return new Car()作为车辆库;
我猜为什么是这样:
由于
VehicleBase
的通用类型实例不相关,因此无法证明强制转换它们可以工作:

如果
T
类型为
Blah
,则转换将不起作用。您不能返回到object,然后使用另一个分支(毕竟C#中没有多重继承)


通过将其强制转换回之前的
对象
,您再次打开了强制转换可能会起作用的可能性,因为仍然可能有一条路径下到
车辆库
。当然,一个界面可以出现在
对象
下面的树中的任何位置,因此也应该可以使用

这既不是编译器的缺陷,也不是故意的决定。泛型类上的类型参数为,即同一泛型类的专门化之间没有继承关系。从文档中:

在.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();
        }
    }
}
接口IWheel
{
}
车轮类别:IWheel
{
}
接口山核桃基
{
}
等级:IVehicleBase
{
}
等级车辆工厂
{
公共静态IVehicleBase GetNew()
{
if(类型(T)=类型(车轮))
{
归还(IVehicleBase)新车();
}
其他的
{
抛出新的NotSupportedException();
}
}
}
有关更多信息和示例,请选中“”


在C#FAQ博客上还有一个提供更多信息的博客,以及一个关于这个主题的博客

听起来很合理,但是如果我使用界面,为什么会有不同呢?这是我不明白的。这不仅仅是因为这是不可证明的。只有泛型接口才能具有变量类型。即使指定了适当的类型约束,此代码也无法工作。这是我使用的解决方案。谢谢你提醒我界面/代理的差异-这很有意义,回答了我的问题。谢谢你提醒我。当你只需要把一些代码拿出来的时候,它太容易忘记了