0

I'm just wondering why passing a System.Collections.Generic.List<string> into this function test(ICollection<object> t) will not work, why can't I pass it in like passing a string into test2(object t)?

Doesn't make much sense to me!

jason
  • 236,483
  • 35
  • 423
  • 525
Isaac Bolinger
  • 7,328
  • 11
  • 52
  • 90
  • 1
    Please show more information(e.g. code) about your question. – Cheng Chen Aug 06 '10 at 05:13
  • Possible duplicate: http://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variable – Adam Lear Aug 06 '10 at 05:15
  • Please provide the full declaration of the type "List". Do you mean System.Collections.Generic.List, System.Collections.ArrayList, System.Collections.SortedList, or is it a class you implemented yourself? – Manfred Aug 06 '10 at 05:16
  • 1
    http://msdn.microsoft.com/en-us/library/dd799517.aspx – Yuriy Faktorovich Aug 06 '10 at 05:17

4 Answers4

7

Because ICollection isn't an output only interface, it is not covariant.

Consider this code:

void test(ICollection<object> t)
{
    t.Add(new TextBox());
}

List<string> lst;
test(lst);

What is supposed to happen when test tries to stuff a TextBox into a List<string>?

The contract for ICollection<object> is that any object can be put in, and items coming out will always be of type object. But List<string> only meets half that contract.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

Because in C# 3.0 and .NET 3.5 or prior List<T> implements ICollection<T>. That means that the generic type of both List and ICollection must be the same. In this scenario List<sting> cannot be assigned to List<object> although string is derived from object. In the same way List<string> cannot be assigned to ICollection<object>.

In C# 4.0 and .NET 4.0 we have the concept of covariance and contra-variance that allow you to assign a List<string> to a IEnumerable<object>.

here is a piece of code that works in C# 4.0

public static void Test(IEnumerable<object> input) {
    // do something
}

static void Main(string[] args) {
    var input = new List<string>();
    Test(input);
}
Andre Vianna
  • 1,713
  • 2
  • 15
  • 29
  • 1
    WRT to the last sentence: no they don't. `ICollection` is (correctly) invariant even in .NET versions that support generic variance (which actually includes .NET 3.5 as well as 4.0). – Ben Voigt Aug 06 '10 at 05:19
0

Method test() expects the parameter value to be of a type that implements the interface ICollection<object>. Make sure class List does.

Manfred
  • 5,320
  • 3
  • 35
  • 29
0

@Ben's explanation is great and yes @Gallahad suggested, there are useful covariant and contravariant interfaces implemented in .Net 4.0. These allow you to do something like what you were trying to do, and guarantee that the pitfall code in Ben's example can't be written with them.

Meanwhile, you can of course do something like

private static void PrintAll<T>(IEnumerable<T> list)
{
     foreach (var item in list)
     {
          Console.WriteLine(item.ToString());
     }
}

static void Main()
{
     List<int> numbers = Enumerable.Range(1, 10).ToList();
     PrintAll(numbers);
}

this is a good way to achieve covariance. Furthermore, you can restrict what PrintAll's generic argument to a convenient base class using where clause.

Om Deshmane
  • 808
  • 6
  • 11