简体   繁体   English

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

[英]C# casting with generics that use interfaces

I have some generic interfaces and classes that implement those intefaces like so: 我有一些通用的接口和类来实现这些接口,如下所示:

    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
    {

    }

I know it seems like a very messy way of doing things, but I sort of need it for my application. 我知道这似乎是一种非常混乱的做事方式,但我对我的应用程序有点需要它。 My question is how come I can't do this: 我的问题是我怎么能不这样做:

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

Variance needs to be explicit (and requires C# 4.0); 方差需要明确(并且需要C#4.0); for example, this makes it compile as covariant (note the out modifiers in the interface): 例如,这使它编译为协变(注意界面中的out修饰符):

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

}

Note, however, that this also limits your interface to ... covariance! 但请注意,这也限制了您的界面......协方差! You couldn't have an Add(M) method, for example - as that would need to be contavariant (aka in ). 例如,你不可能有Add(M)方法 - 因为它需要是contavariant(aka in )。

Marc is right; 马克是对的; just to give you some more background on why this cannot work. 只是为了给你一些关于为什么这不起作用的背景知识。 Consider the following re-naming of your code: 请考虑以下重新命名代码:

    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
    {
    }

And now your question is, why is this not legal: 现在你的问题是,为什么这不合法:

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

?

Because suppose now there is a method on IZoo: 因为现在假设IZoo上有一个方法:

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

And you then say: 然后你说:

zoo.PutAnimalInCage(giraffePaddock, giraffe);

And you just put a giraffe paddock into an aquarium! 而你只需将长颈鹿围场放入水族馆! We cannot maintain type safety in a world where the conversion you want is legal and IZoo can have any method you choose on it. 在您想要的转换是合法的世界中我们无法保持类型安全,IZoo可以使用您选择的任何方法。

Now, this is only dangerous because IZoo has such a method. 现在,这只是危险的,因为IZoo有这样的方法。 If it doesn't have such a method then you are right, that could be perfectly safe. 如果它没有这样的方法那么你是对的,这可能是非常安全的。 In C# 4.0 we added a feature to the language so that you can ask the compiler "check whether this interface can be made safely variant", by annotating the type parameters you want to be covariant with "out", and the ones you want to be contravariant with "in". 在C#4.0中,我们为该语言添加了一个功能,以便您可以通过注释要与“out”协变的类型参数以及您想要的类型参数来询问编译器“检查此接口是否可以安全变换”。与“在”逆时针。 If you do that then the compiler will check for you whether the variance you want can be made to be typesafe. 如果您这样做,那么编译器将检查您是否可以使您想要的方差是类型安全的。 If it cannot, then it will not allow the declaration of the type. 如果不能,则不允许声明类型。

The way this question usually comes up on StackOverflow is people asking why is this illegal: 这个问题通常出现在StackOverflow上的方式是人们问为什么这是非法的:

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

Same reason. 同样的道理。 Because then nothing stops you from later 因为之后没有什么能阻止你

mammals.Add(new Tiger());

and you've just added a tiger to a list of giraffes. 而你刚刚将一只老虎添加到长颈鹿名单中。 Same reasoning, just a much simpler case. 同样的道理,只是一个更简单的案例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM