0

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?

ca9163d9
  • 27,283
  • 64
  • 210
  • 413

1 Answers1

7

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, can you elaborate "take a step back"? – ca9163d9 Sep 14 '12 at 06:39
  • @NickW: Well, we don't know the bigger picture here - why you've got those types. See if you can accomplish the same bigger goal *without* requiring covariance. – Jon Skeet Sep 14 '12 at 10:49
  • Originally I have only Header and Item. Later I found that there are other classes which is similar to HeaderA and ItemA and only have a small difference. So Header and Item become HeaderA, HeaderB, ... and ItemA, ItemB, .... – ca9163d9 Sep 14 '12 at 14:33
  • @NickW: That's not really enough of a context to help, to be honest. I think you're likely to have to try to work this out for yourself. – Jon Skeet Sep 14 '12 at 14:51
  • Actually the design is about another question. http://stackoverflow.com/questions/12410890/type-constraint – ca9163d9 Sep 14 '12 at 18:05
  • @NickW: Well that's not really a full *design* question - that's just assuming the design you want, and finding out the syntax to do it... I'm suggesting a *wider* redesign. – Jon Skeet Sep 15 '12 at 06:10