将List <T>强制转换为List <Interface>


Answers:


249

您不能强制转换(保留参考身份)-那是不安全的。例如:

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

现在你可以转换List<Apple>IEnumerable<IFruit>在.NET 4 / C#4,由于协方差,但如果你想有一个List<IFruit>你必须建立一个新的列表。例如:

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

但是,这是一样的铸造原名单-因为现在有两个单独的列表。这是安全的,但是您需要了解对一个列表所做的更改不会在另一列表中显示。(当然,将看到对列表所引用对象的修改。)


6
就像他们“仍在大楼里”一样!
安德拉斯·佐坦

1
执行协方差tolist和执行新的List <IFruit>()之间有什么区别?然后遍历原始列表并将每个项目添加到IFruit列表中?以foreach的方式...对象引用将相同,对吗?所以...如果是真的,那么就我个人而言,您不能直接投射整个列表就没有意义。?
罗伯特·诺亚克

3
@RobertNoack:“对象引用”是什么意思?每个元素的对象引用都是相同的,但这与强制转换列表引用本身不同。假设您可以强制转换引用,以便您拥有一个编译时类型List<IFruit>的引用,该引用实际上是对的引用List<Apple>。如果添加Banana对此的引用,您会期望发生List<IFruit>什么?
乔恩·斯基特

1
哦。我想我需要学习如何阅读。我以为原始答案说列表中的对象将被深复制并重新创建,这对我来说没有意义。但是我显然错过了只用相同对象创建新列表的部分。
罗伯特·诺亚克

2
@TrươngQuốcKhánh:我不知道您的任何代码是什么样,或者您是否有针对的using指令System.Linq,或者您想调用它的内容,我不确定您希望我如何提供帮助。我建议您进行更多研究,如果仍然遇到问题,请使用可复制性最小的示例来提问。
乔恩·斯基特

6

Cast迭代器和.ToList():

List<IDic> casted = input.Cast<IDic>().ToList() 会成功的

最初,我说协方差是可行的-但正如乔恩正确指出的那样;不,不会!

最初我也愚蠢地拒绝了ToList()电话


Cast返回一个- IEnumerable<T>,而不是List<T>-,并且不,协方差不允许这种转换,因为这将是不安全的-请参阅我的答案。
乔恩·斯基特

在您链接到的页面上:“仅接口类型和委托类型可以具有变量类型参数”
Jon Skeet 2012年

@Jon- ToList()在阅读您的评论之前,我已经意识到缺少;但是是的,正如您所展示的,协方差当然是行不通的!h!
安德拉斯·佐坦

对。协方差仍然可以提供帮助,因为这意味着您Cast只要在.NET 4中指定类型参数,就不需要在.NET 4中进行调用ToList
乔恩·斯基特

5

我也遇到了这个问题,在阅读了Jon Skeet的回答后,我将代码从using修改List<T>为use IEnumerable<T>。虽然这并不回答OP的原始的问题,我怎么能投List<Client>List<IDic>,但它避免了这样做的必要,因此可能会有所帮助别人谁遇到此问题。当然,这假定需要使用的代码List<IDic>在您的控制之下。

例如:

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

代替:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

如果可以使用LINQ,则可以执行此操作...

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();

3
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();

0

只有通过创建新List<IDic>元素并转移所有元素,才有可能。


有什么评论为什么会被否决,因为一般意义与所有其他答案相同?
Piotr Auguscik '01年

我的猜测是您被拒绝了,因为您说只能创建一个新列表,但是其他人则发布了相反的信息……虽然不是我的反对)
musefan 2012年

好吧,他们确实创建了新列表,但是没有使用新的运算符,这不会改变事实。
Piotr Auguscik'1

0

在.Net 3.5中,您可以执行以下操作:

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

在这种情况下,List的构造函数采用IEnumerable。
列表虽然只能转换为IEnumerable。即使myObj可以转换为ISomeInterface,IEnumerable类型也不能转换为IEnumerable。


问题是,大多数情况下您想对原始列表进行操作,因此会复制该列表
滚动
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.