为什么我不能将对象强制转换为约束泛型?

时间:2015-10-09 09:53:00

标签: c# generics casting

鉴于我有以下接口和一个实现它的类:

public interface IAnimal
{
    void Feed();
}

public class Animal : IAnimal
{
    public void Feed()
    {
        // feed
    }
}

当我的Animal类实现它时,为什么不能从我的具体类转换为通用约束为IAnimal?

public class Zoo
{
    private readonly Animal animal = new Animal();

    public TAnimal GetAnimal<TAnimal>() where TAnimal : IAnimal
    {
        return (TAnimal)(this.animal); // This will not compile
    }
}

如果我将动物的野外类型更改为IAnimal而不是Animal,那么它编译好了:

public class Zoo
{
    private readonly IAnimal animal = new Animal();

    public TAnimal GetAnimal<TAnimal>() where TAnimal : IAnimal
    {
        return (TAnimal)(this.animal); // this compiles
    }
}

或者如果我在强制转换为通用TAnimal之前对IAnimal进行显式转换,那么这也可以正常编译:

public class Zoo
{
    private readonly Animal animal = new Animal();

    public TAnimal GetAnimal<TAnimal>() where TAnimal : IAnimal
    {
        return (TAnimal)((IAnimal)this.animal); // this compiles
    }
}

所以我的问题是 - 为什么第一个版本不起作用?当然编译器有足够的信息来知道Animal实现了IAnimal,所以给定约束将它转换为TAnimal是有效的吗?或者我在这里缺少什么?

2 个答案:

答案 0 :(得分:4)

Animal继承自IAnimalTAnimal不会继承自Animal,也来自IAnimal。如果A未从B继承,则无法从B投射到A,它将类似于:

DataTable dt = new DataTable();
string str = (string)dt;

即使DataTablestring继承自object,也无法执行此操作。要在继承无关的类型之间进行转换,您必须定义conversion operators

答案 1 :(得分:1)

假设您还有一个班级Dog

public class Dog : IAnimal 
{

} 

如果您调用方法:GetAnimal<TAnimal>() DogTAnimal,您将获得如下代码:

public class Zoo
{
    private readonly Animal animal = new Animal();

    public Dog GetAnimal()
    {
        return (Dog)this.animal;
    }
}

当然Dog不会从Animal继承,因此投射错误。

然后你有了第二个例子:

public class Zoo
{
    private readonly IAnimal animal = new Animal();

    public Dog GetAnimal()
    {
        return (Dog)this.animal;
    }
}

Dog正在实施IAnimal,所以这将编译。但是它会在运行时抛出InvalidCastException。同样的事情适用于第三个例子中的双重投射:

public class Zoo
{
    private readonly Animal animal = new Animal();

    public Dog GetAnimal()
    {
        return (Dog)(IAnimal)this.animal;
    }
}

您可以从Animal投射到IAnimal以及从IAnimal投射到Dog,但它会投掷InvalidCastException