使用使用接口的泛型进行 C# 强制转换

本文关键字:转换 接口 泛型 | 更新日期: 2023-09-27 17:55:24

我有一些通用接口和类来实现这些接口,如下所示:

    interface A<M, N>
        where M : X<N>
        where N : Y
    {
    }
    class B<M, N> : A<M, N>
        where M : X<N>
        where N : Y
    {
    }
    interface X<M> where M : Y
    {
    }
    interface Y
    {
    }
    class X1<M> : X<M> where M : Y
    {
    }
    class Y1 : Y
    {
    }

我知道这似乎是一种非常混乱的做事方式,但我有点需要它来申请。我的问题是为什么我不能这样做:

A<X<Y>, Y> variable = new B<X1<Y1>, Y1>();

使用使用接口的泛型进行 C# 强制转换

Marc是对的

;只是为了给你更多的背景知识,为什么这行不通。请考虑对代码进行以下重命名:

    interface IZoo<TCage, TAnimal>
        where TCage : ICage<TAnimal>
        where TAnimal : IAnimal
    {
    }
    class Zoo<TCage, TAnimal> : IZoo<TCage, TAnimal>
        where TCage : ICage<TAnimal>
        where TAnimal : IAnimal
    {
    }
    interface ICage<TAnimal> where TAnimal : IAnimal
    {
    }
    interface IAnimal
    {
    }
    class FishTank<TAnimal> : ICage<TAnimal> where TAnimal : IAnimal
    {
    }
    class Fish : IAnimal
    {
    }

现在你的问题是,为什么这不合法:

Zoo<FishTank<Fish>, Fish> aquarium = new Zoo<FishTank<Fish>, Fish>();
IZoo<ICage<IAnimal>, IAnimal> zoo = aquarium;

因为假设现在在 IZoo 上有一个方法:

    interface IZoo<TCage, TAnimal>
        where TCage : ICage<TAnimal>
        where TAnimal : IAnimal
    {
        void PutAnimalInCage(TCage cage, TAnimal animal);
    }

然后你说:

zoo.PutAnimalInCage(giraffePaddock, giraffe);

你只是把长颈鹿围场放进水族馆!在您想要的转换是合法的世界中,我们无法维护类型安全,IZoo 可以使用您选择的任何方法。

现在,这很危险,因为IZoo有这样的方法。如果它没有这样的方法,那么你是对的,这可能是完全安全的。在 C# 4.0 中,我们在语言中添加了一个功能,以便您可以询问编译器"检查此接口是否可以安全变体",方法是用"out"注释要协变的类型参数,以及要与"in"逆变的类型参数。 如果这样做,则编译器将为您检查是否可以使所需的方差是类型安全的。 如果不能,则不允许声明该类型。

这个问题通常在StackOverflow上出现的方式是人们问为什么这是非法的:

List<Giraffe> giraffes = new List<Giraffe>();
List<Mammal> mammals = giraffes; // illegal

同样的原因。因为那时没有什么能阻止你以后

mammals.Add(new Tiger());

你刚刚在长颈鹿列表中添加了一只老虎。 同样的推理,只是一个更简单的情况。

方差需要显式(并且需要 C# 4.0);例如,这使其编译为协变(请注意接口中的out修饰符):

interface A<out M, out N>
    where M : X<N>
    where N : Y
{
}
interface X<out M> where M : Y
{
}

但是请注意,这也将您的界面限制为...协方差!例如,您不能使用Add(M)方法 - 因为这需要是可变的(又名 in )。