5

I'm sure I'm missing something here, but any particular reason this doesn't work?

public ObservableCollection<object> ItemCollection { get; set; }

private void SetListData<T>(List<T> MyList)
{
    ItemCollection = new ObservableCollection<object>(MyList);
}

Is there some value for T where this won't work? I figure collection of objects would cover every case, but it seems not:

Error 2 Argument 1: cannot convert from 'System.Collections.Generic.List<T>' to 'System.Collections.Generic.List<object>'

Changing the signature of the property would cause a whole new set of problems, so changing it to:

ItemCollection = new ObservableCollection<T>(MyList);

doesn't seem like a good solution. Can anyone tell me why my original code doesn't work, and if there is any easy fix?

Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138

3 Answers3

7

You have a couple of options:

private void SetListData<T>(List<T> MyList) where T : class

or

ItemCollection = new ObservableCollection<object>(MyList.Cast<object>());

If you had a List<T> of a known reference type, it could work, even though the type parameter is not object:

var list = new List<string>();
var observable = new ObservableCollection<object>(list);

But in this case you are using the generic parameter, which is not a known reference type; it could be a value type/struct. These can be "boxed" as objects but are not inherently objects.

Thus, you must either constrain that parameter to always be a reference type, or allow any type T and do an explicit cast to object inside the body of the method.

Jay
  • 56,361
  • 10
  • 99
  • 123
  • I think just snippets of code with no explanation are not very useful. – svick Jun 19 '13 at 13:47
  • Out of curiosity, why does this work `where T : class`, I guess it prevents me from passing an interface? – Kevin DiTraglia Jun 19 '13 at 13:49
  • If you have a list of known type `int`, it wouldn't work (at least not without the `Cast`). – svick Jun 19 '13 at 13:52
  • @KevinDiTraglia It's kind of confusing, but it does not prevent from `T` being an interface. It does prevent it from being a value type (like `int` or a `struct`). – svick Jun 19 '13 at 13:54
  • @Jay Not really, `struct`s can also implement interfaces. `T` cannot be a value type, but the list can contain (boxed) instances of value types. – svick Jun 19 '13 at 14:19
2

You're almost there. List<T> is convertible to IEnumerable<object> (thanks to covariance) only when T is a reference type. So, limiting T to be a reference type is going to work:

private void SetListData<T>(List<T> MyList) where T : class
{
    ItemCollection = new ObservableCollection<object>(MyList);
}
svick
  • 236,525
  • 50
  • 385
  • 514
  • I think you're missing something. The code you posted is identical to the non-working code posted by the OP. – Jay Jun 19 '13 at 13:47
1

The problem is that "T" is not "object", even though "T" inherits "object". The types in the generic lists must be the same.

Your best solution would be as follows:

ItemCollection = new ObservableCollection<object>();
foreach(T item in MyList)
{
    ItemCollection.Add(item);
}
Russ
  • 4,091
  • 21
  • 32