15

Given the following types:

public interface IMyClass { }
public class MyClass : IMyClass { }

I wonder how can I convert a List<MyClass> to a List<IMyClass>? I am not completely clear on the covariance/contravariance topics, but I understand that I cannot just plainly cast the List because of that.

I could come up with this trivial solution only; lacking any elegance, wasting resources:

...
public List<IMyClass> ConvertItems(List<MyClass> input)
{
   var result = new List<IMyClass>(input.Count);
   foreach (var item in input)
   {
       result.Add(item);
   }
   return result;
}
....

How can you solve it in a more elegant/performant way?

(Please, mind that I need .NET 2.0 solution, but for completeness, I would be happy to see the more elegant solutions using newer framework versions, too.)

abatishchev
  • 98,240
  • 88
  • 296
  • 433
user256890
  • 3,396
  • 5
  • 28
  • 45

3 Answers3

24

The simplest way is probably to use ConvertAll:

List<IMyClass> converted = original.ConvertAll<IMyClass>(x => x);

Even if you're using .NET 2, you can use lambda syntax if you're using VS2008 or higher. Otherwise, there's always anonymous methods:

List<IMyClass> converted = original.ConvertAll<IMyClass>(
    delegate (MyClass x) { return x; });

In .NET 3.5 you could use LINQ with Cast, OfType or even just Select:

var converted = original.Cast<IMyClass>().ToList();
var converted = original.OfType<IMyClass>().ToList();
var converted = original.Select(x => (IMyClass) x).ToList();

In .NET 4.0 you can use ToList directly without an intermediate cast, due to the covariance of IEnumerable<T>:

var converted = original.ToList<IMyClass>();
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Does it need to be a list? An IEnumerable solution could be more efficient:

 public IEnumerable<IMyClass> ConvertItems(List<MyClass> input)
 {
    foreach (var item in input)
    {
        yield return (IMyClass)item;
    }
 } 
cjk
  • 45,739
  • 9
  • 81
  • 112
  • 1
    It is worth saying that you don't necessarily need to do this to use an IEnumerable solution. The method could just do `return input;`. It would mean that the underlying object was still the list and so you could go back to it - a problem you don't find with the above method. But Covariance means that a direct cast to `IEnumerable` is very possible. Not sure if this is a new change since this answer was first made 7 years ago. I don't keep track of the history of c# but it is certainly valid now. :) – Chris Mar 08 '18 at 09:29
0

(.NET 3.5 solution)

List<MyClass> list = new List<MyClass> { ... };
List<IMyClass> converted = list.Cast<IMyClass>().ToList();
abatishchev
  • 98,240
  • 88
  • 296
  • 433