简体   繁体   English

如何转换通用列表 <T> 到基于接口的列表 <T>

[英]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. 你需要.NET 3.5。 I believe the Cast extension method can be found in System.Linq. 我相信Cast扩展方法可以在System.Linq中找到。

You can't. 你不能。 Because List<T> and ILIst<T> to only support invariant type parameters. 因为List<T>ILIst<T>只支持不变类型参数。 This is down to T being both use for input and output parameters (eg return values). 这归结为T既用于输入和输出参数(例如返回值)。 Otherwise you can break the type safety. 否则你可以打破类型安全。

Other interfaces (eg IEntumerable<T> ) do allow some variance. 其他接口(例如IEntumerable<T> )确实允许一些差异。

See Eric Lippert's blog " Fabulous Adventures In Coding " for discussion of contra- and co-variance. 有关反对和共同变化的讨论,请参阅Eric Lippert的博客“ 编码中的神奇冒险 ”。 Specifically the " Covariance and Contravariance " tag. 特别是“ 协方差和逆变 ”标签。

Edit, just added to the "C# Frequently Asked Questions" blog: Covariance and Contravariance FAQ 编辑,刚刚添加到“C#常见问题”博客: Covariance和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: 您所指的是通用协方差,并且不受c#3支持。但是,它受到c#4(.NET 4 / VS 2010)的支持,您可以在此处阅读更多相关内容:

Variance in Generic Interfaces 通用接口的方差

Having said that, IList<T> is not covariant (because it both accepts and exposes T ). 话虽如此, IList<T>不是协变的(因为它接受并暴露了T )。 IEnumerable<T> , on the other hand, is covariant (because it doesn't accept T ). 另一方面, IEnumerable<T>是协变的(因为它不接受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. 对于instnce,将List<Shape>List<object>将导致任何类型的对象都可以添加到列表中,这将完全不一致。

You can also do: 你也可以这样做:

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

Or if you are doing this in .NET 2.0: 或者如果你在.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. 您需要创建一个新列表并通过迭代原始列表或使用ConvertAll来填充它。 See http://www.dev102.com/2008/05/15/how-to-convert-listt1-to-listt2/ for sample code. 有关示例代码,请参见http://www.dev102.com/2008/05/15/how-to-convert-listt1-to-listt2/

This works if you define allShapes as IEnumerable 如果将allShapes定义为IEnumerable,则此方法有效

In C# 4.0 you may simply assign allshapes=cubes 在C#4.0中,您可以简单地指定allshapes = cubes

For C# 3.5 you could use allShapes = cubes.Select(c=>((Shape)c)); 对于C#3.5,您可以使用allShapes = cubes.Select(c =>((Shape)c));

But in any case you need to use IEnumerable instead of List 但无论如何你需要使用IEnumerable而不是List

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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