James Orr
James Orr

Reputation: 5135

Covariance/Conversion issue with Generics

Consider the code:

using System.Collections.Generic;
namespace TestingTypes
{
    class Program
    {
        static void Main(string[] args)
        {
            var strings = new List<string>();               
            INeedToPassThisMethodAListOfObjects(strings as List<object>);
        }

        static void INeedToPassThisMethodAListOfObjects(List<object> objects) { }
    }
}

1>------ Build started: Project: TestingTypes, Configuration: Debug Any CPU ------
1>c:\users\[censored]\TestingTypes\Program.cs(9,41,9,64): error CS0039: Cannot convert 
type 'System.Collections.Generic.List<string>' to 
'System.Collections.Generic.List<object>' via a reference conversion, boxing 
conversion, unboxing conversion, wrapping conversion, or null type conversion

You might say that a List<string> is a List<object>, since a string is an object and C# 4 is supposed to support covariance in generic types.

Upvotes: 2

Views: 1483

Answers (3)

Pluc
Pluc

Reputation: 2929

You have to convert the strings to objects. Theres a nice LINQ method to do so.

var strings = new List<string>();               
INeedToPassThisMethodAListOfObjects(strings.Cast<object>());

Edit

According to your own link,

In C#, variance is supported in the following scenarios:

  • Covariance in arrays (since C# 1.0)

  • Covariance and contravariance in delegates, also known as “method group variance” (since C# 2.0)

  • Variance for generic type parameters in interfaces and delegates (since C# 4.0)

So IEnumerable would accept List

Upvotes: 2

Justin Niessner
Justin Niessner

Reputation: 245419

You're getting the error because a List<string> is not a List<object>.

You can call list.Add(new TextBox()) on List<object> but, obviously, the same call doesn't work on List<string>.

C# Generics only allow for Covariance if the generic type is immutable (which is my the cast from List to IEnumerable works).

If you need to pass the list to a method, you could try passing

listOfStrings.Cast<object>();

On the downside, if you use that solution, any modifications made to the list inside the method call will not be reflected in the original list (because the call to Cast creates a new list).

If you have control of the method INeedToPassThisMethodAListOfObjects and that method only needs to iterate over the collection rather than modify it, you can change the parameter type to be IEnumerable<object> in which case you'd simply be able to pass your List<string> without any issues.

Upvotes: 3

Tim Rogers
Tim Rogers

Reputation: 21713

Interfaces can be variant; classes cannot. See here for the explanation.

Your code will work if you pass the strings collection uncasted and change the declaration to be

static void INeedToPassThisMethodAListOfObjects(IEnumerable<object> objects) { }

However, that depends on whether you need a List within this function.

Upvotes: 3

Related Questions