简体   繁体   中英

How to convert a generic List<T> to an Interface based List<T>

I am sure I am missing something simple, however I am trying to convert a strongly typed list of objects that all implement an interface in to a list of that interface type.

Below is a sample to demonstrate the error:

public void ExampleCode(){
    List<Cube> cubes = new List<Cube>();
    List<Shape> allShapes;
    allShapes = cubes;//Syntax Error
    allShapes = (List<Shape>)cubes;//Syntax Error  
}

public class Cube : Shape
{
    public int ID { get; set; }
    public int Sides { get; set; }
}

public interface Shape
{
  int ID { get; set; }
  int Sides { get; set; }
}

Instead of casting like that, try:

allShapes = cubes.Cast<Shape>().ToList();

You need .NET 3.5 for this. I believe the Cast extension method can be found in System.Linq.

You can't. Because List<T> and ILIst<T> to only support invariant type parameters. This is down to T being both use for input and output parameters (eg return values). Otherwise you can break the type safety.

Other interfaces (eg IEntumerable<T> ) do allow some variance.

See Eric Lippert's blog " Fabulous Adventures In Coding " for discussion of contra- and co-variance. Specifically the " Covariance and Contravariance " tag.

Edit, just added to the "C# Frequently Asked Questions" blog: Covariance and Contravariance FAQ

What you are referring to is called generic covariance and is not supported by c# 3. It is, however, supported by c# 4 (.NET 4 / VS 2010) and you can read more about it here:

Variance in Generic Interfaces

Having said that, IList<T> is not covariant (because it both accepts and exposes T ). IEnumerable<T> , on the other hand, is covariant (because it doesn't accept T ).

You cannot do this since by casting this way you can potentially lose all type safety. For instnce, casting List<Shape> to List<object> will result in that objects of any type can be added to the list, which will be downright inconsistent.

You can also do:

allShapes = cubes.ConvertAll(x => (Shape)x);

Or if you are doing this in .NET 2.0:

allShapes = cubes.ConvertAll<Shape>(delegate(Cube c){
    return (Shape)c;
});

You can't cast between lists of types, even if the types themselves are convertible. You will need to create a new list and populate it, either by iterating the original list or by using ConvertAll. See http://www.dev102.com/2008/05/15/how-to-convert-listt1-to-listt2/ for sample code.

This works if you define allShapes as IEnumerable

In C# 4.0 you may simply assign allshapes=cubes

For C# 3.5 you could use allShapes = cubes.Select(c=>((Shape)c));

But in any case you need to use IEnumerable instead of List

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM