5

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>();

2 Answers 2

8

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:

    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.

Now, this is only dangerous because IZoo has such a method. 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". 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:

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.

Sign up to request clarification or add additional context in comments.

Comments

8

Variance needs to be explicit (and requires C# 4.0); for example, this makes it compile as covariant (note the out modifiers in the interface):

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).

4 Comments

hey, When I try do that, it says its C#4.0 language feature and I get an error, what should I do?
@Twinhelix - what version of Visual Studio are you using, and what platform version are you targetting? It works for me on VS2010 targetting .NET 2.0. Before C# 4.0... variance was kinda not there exceot for very limited cases.
Hey I'm running VS2008 and .NET 3.5. I can't really change my environment set up, is there any way around this problem?
I can't upgrade as this is the company's computer, lot's of privileges and other others. Was hoping there was a work around :P

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.