Matt
Matt

Reputation: 1422

Generics with inheritance and interfaces - why doesn't this work?

Here's my entire application. To me, this should compile fine.

namespace SampleApp
{
    interface I<T> where T : Image
    {
    }

    class A<T> where T : Image
    {
    }

    class B : A<Bitmap>, I<Bitmap>
    {
    }

    class C : A<Metafile>, I<Metafile>
    {
    }

    class Program
    {
        public static I<Image> SomeProperty { get; set; }

        static void Main(string[] args)
        {
            B b = new B();            
            SomeProperty = b;

            C c = new C();
            SomeProperty = c;
        }
    }
}

However, The lines "SomeProperty = b" and "SomeProperty = c" give the error:

Cannot implicitly convert type 'B' to 'I<System.Drawing.Image>'. An explicit conversion exists (are you missing a cast?)

But I can't work out why. B implements I<Bitmap>, and Bitmap is a subclass of Image, so surely, by definition, B implements I<Image>.

Upvotes: 1

Views: 646

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1500155

As Sasha says, you're looking for generic covariance. This may or may not be appropriate depending on what your interface members look like. If you only ever take values "out" of the interface, you can make your code compile by making T covariant:

interface I<out T> where T : Image
{
}

However, if you have any methods accepting T, e.g.

void ReplaceWith(T newImage)

then you can't make T covariant.

Generic variance is a complicated topic - I gave a talk at NDC 2010 which you may find useful. You can watch it at the NDC video site. Search for "variance" to find it quickly. (The real content starts at about 2 minutes.)

Upvotes: 3

decyclone
decyclone

Reputation: 30830

Change your interface to following to make it work:

interface I<out T> where T : Image
{
}

It is called Covariance. Read following link for more information:

Covariance and Contravariance FAQ

Upvotes: 1

Sasha Goldshtein
Sasha Goldshtein

Reputation: 3519

No, it doesn't work that way with generics. A may be a subclass of B, but G<A> is not a subclass of G<B>. The same goes for interfaces.

You might be looking for a feature called generic covariance/contravariance, but to determine if you can use it in this case you would need to show us the real contents of the interface.

Upvotes: 2

Related Questions