ca9163d9
ca9163d9

Reputation: 29227

Is it Covariance and Contravariance related issue?

I have the following code:

class Header<TItem> where TItem : IItem { IEnumerable<TItem> Item { get; set; } }
class HeaderA : Header<ItemA> { public HeaderA(int a) {...} } 
class HeaderB : Header<ItemB> { public HeaderB(int b) {...} } 

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

public static List<Header<IItem>> list = new List<Header<IItem>> 
{
    new HeaderA(1)
}

The compile error on the last new HeaderA(1) is

Error   1   The best overloaded Add method
'System.Collections.Generic.List<NS.Header<NS.IItem>>.Add(NS.Header<NS.IItem>)'
for the collection initializer has some invalid arguments

How to fix the issue?

Upvotes: 0

Views: 139

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1503499

You're trying to add a Header<ItemA> to a List<Header<IItem>>. That requires a conversion from Header<ItemA> to Header<IItem> - and that conversion doesn't exist. It doesn't exist for a good reason. Imagine your code was valid... then this would work:

List<Header<IItem>> list = ...; // As per code
Header<IItem> header = list[0];
header.Item = new List<IItem>();

Now remember that header is actually a HeaderA - so this working is equivalent to this HeaderA header = new HeaderA(); header.Item = new List { new ItemB() };

That's not good when anything else would expect header.Item to be an IEnumerable<ItemA>(); - so this should be okay:

ItemA itemA = header.Item.First();

... and clearly won't if you've added an ItemB in there.

Basically, you're looking for generic covariance - but you can only declare that on interfaces and delegates (not on classes such as Header<TItem>), and only when the type parameter isn't used in an input position as it is here due to the Item setter.

Perhaps more importantly, your design looks extremely complicated - I strongly suspect that if you take a step back, you can design your way around trying to do this in the first place.

Upvotes: 7

Related Questions