1

Possible Duplicate:
In C#, why can't a List<string> object be stored in a List<object> variable

Say that you have a class that triggers events with collections of different classes. You want to take those collections and instantiate an object that takes a List<object> as parameter to it's constructor (you need the methods of IList: indexed accessed, indexOf etc).

What is the best practice?

If the events return List or IList you have to do some nasty casting when creating it from a List of a more specific class, say List<SomeClass> because IList is invariant.

new DataObject(someClasses.Cast<object>().ToList())

You can use Enumerable<whatever> in the events, then at least you can simply do new DataObject(someClasses.ToList()) but a new List still has to be created which might have some overhead...

It seems a little weird that Lists can't be downcasted to object automatically

Community
  • 1
  • 1
Homde
  • 4,246
  • 4
  • 34
  • 50

1 Answers1

1

The problem is your methods that take List<object> as a parameter. Options:

  • Make them take IEnumerable<object>
  • Make them generic, taking List<T>

Here's why you can't convert (say) a List<string> to a List<object>:

List<string> strings = new List<string>();
List<object> objects = strings;
objects.Add(new Button());
string text = strings[0];

Clearly that can't "work" at execution time, so it's better that it's prohibited at compile time. Lines 1, 3 and 4 all look fine to me - so it's got to be line 2 that causes the problem, which indeed is the way the language is designed. How would you suggest the language could have been designed to make the above "safe"?

For a lot more about generic variance, see my NDC 2010 talk on the topic - go to the NDC video page and search for "variance".

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Did you mean `string text = objects[0]` ? – Chris S Mar 01 '11 at 11:32
  • I see the problem and in this case it's mostly an issue because I require IList rather than IEnumerable. Unfortunately I can't make the class generic in this instance. I guess a nice solution perhaps would be that when you try to pass a more specific List to something requiring a lesser that instance is automatically wrapped in a ReadOnlyCollection – Homde Mar 01 '11 at 11:47
  • @Chris: No, but I did mean `objects = strings` in the second line :) – Jon Skeet Mar 01 '11 at 11:47
  • @mko: You think that's something the *language* should be doing for you? Definitely not, IMO. By all means create your own extension method to make that simpler, but the language rules for variance shouldn't be messing with specific collection types. – Jon Skeet Mar 01 '11 at 11:48
  • Maybe doing that implicitly is a bit confusing but perhaps it could be done explicitly through some language feature. And if I do pass a readonly collection of object it's pretty natural behavior to be able to use variance that way don't you think? – Homde Mar 01 '11 at 11:56
  • @mko: Well, it would be if we had an IReadOnlyList interface. It's unfortunate that generic variance doesn't work with classes (only interfaces and delegates) but that's just the way it is. Of course you could create your own such interface and use that in your methods, along with an extension method to convert `IList` to an `IReadOnlyList`, then use the existing variance. – Jon Skeet Mar 01 '11 at 11:58
  • Or why not an Immutable keyword :) That might be an idea, thanks – Homde Mar 01 '11 at 12:07
  • @mko: The C# team have been thinking about immutability, but there haven't been any results from that thinking just yet, as far as I'm aware. I'm ever hopeful for C# 6 though :) – Jon Skeet Mar 01 '11 at 12:08