Isaac Bolinger
Isaac Bolinger

Reputation: 7388

Question about generic function parameter

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!

Upvotes: 0

Views: 199

Answers (4)

Om Deshmane
Om Deshmane

Reputation: 808

@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.

Upvotes: 0

Andre Vianna
Andre Vianna

Reputation: 1732

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);
}

Upvotes: 1

Manfred
Manfred

Reputation: 5666

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

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283634

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.

Upvotes: 7

Related Questions