Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derived type of generic base class

I have the following code.

class Header<T> where T: IItem { }
class HeaderA : Header<ItemA> { } 
class HeaderB : Header<ItemB> { } 

interface IItem { }
class ItemA : IItem { }
class ItemB : IItem { }

Header<IItem> h = new HeaderA();

The last line cannot be compiled.

Cannot implicitly convert type 'UserQuery.HeaderA' to 'UserQuery.Header<UserQuery.IItem>'

HeaderA is a subtype of Header and ItemA is a subtype of IItem. Why it doesn't work?

like image 924
ca9163d9 Avatar asked Dec 05 '22 14:12

ca9163d9


1 Answers

In short, you're trying to use a concept called covariance, which is not supported in .NET generic classes, and not supported by default in interfaces.

If you want to allow the class to do this, you can specify it in C# 3 or later using the out contextual keyword on a generic interface:

interface IHeader<out T> where T : IItem { }
class Header<T>: IHeader<T> where T:IItem { }
class HeaderA : Header<ItemA> { }
class HeaderB : Header<ItemB> { }

interface IItem { }
class ItemA : IItem { }
class ItemB : IItem { }

public void Foo()
{
    //now this works; notice the use of the interface instead of the base class.
    IHeader<IItem> h = new HeaderA();
}

By using the interface with the keyword, you are basically telling the compiler that no usage of the interface will ever have to know more about the generic type than that it meets the constraints of the interface's generic type declaration (or that it's an object). As such, while you can now assign more derived generics to variables of the interface type, you can only deal with them as the interface type, never as any derived type.

The out keyword is not acceptable for class definitions; you cannot force usages of Header<T> to be covariant.

like image 52
KeithS Avatar answered Dec 10 '22 10:12

KeithS