Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 354
Twinhelix Avatar asked May 09 '11 09:05

Twinhelix


People also ask

What do you mean by C?

C is an imperative procedural language supporting structured programming, lexical variable scope, and recursion, with a static type system. It was designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support.

Why is C language used?

The C programming language is the recommended language for creating embedded system drivers and applications. The availability of machine-level hardware APIs, as well as the presence of C compilers, dynamic memory allocation, and deterministic resource consumption, make this language the most popular.

Why is C called a mid level programming language?

C has the features of both assembly level languages i.e low-level languages and higher level languages. So that's why C is generally called as a middle-level Language. The user uses C language for writing an operating system and generates menu driven customer billing system.

Why do we use return 0 in C programming?

return 0: A return 0 means that the program will execute successfully and did what it was intended to do.


1 Answers

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.

like image 86
Eric Lippert Avatar answered Oct 04 '22 06:10

Eric Lippert