2011-05-04 119 views
18

我有一个对象列表,它们是我的类型QuoteHeader,我想将该列表作为对象列表传递给能够接受List<object>的方法。为什么我不能从列表<MyClass>转到列表<object>?

我行代码读取...

Tools.MyMethod((List<object>)MyListOfQuoteHeaders); 

,但我得到在设计时以下错误......

Cannot convert type 'System.Collections.Generic.List<MyNameSpace.QuoteHeader>' 
to 'System.Collections.Generic.List<object>' 

我需要做任何事情上我的课,让这?我认为所有的类都从对象继承,所以我不明白为什么这不起作用?

+2

为什么你想演员列表到列表?我不明白原因,那么泛型的用法是什么。 – 2011-05-04 10:06:01

+0

[C#Cast List to List ](http://stackoverflow.com/questions/5115275/c-cast-listx-to-listy)也可能与[C#]密切相关 - Can List 可能被无情地转换到一个列表或类似?](http://stackoverflow.com/questions/1838687/c-can-a-listmyclass-be-seemlessly-cast-to-a-list- interface- or-similar) – finnw 2011-05-04 10:47:53

+0

如果可能那么你可以将* any *对象添加到列表中。违反“List ”仅包含与Foo分配兼容的对象的规则。你必须创建一个新的列表。 – 2011-05-04 12:25:46

回答

29

的原因,这是不合法的,是因为它是不是安全。假设它是合法的:

List<Giraffe> giraffes = new List<Giraffe>(); 
List<Animal> animals = giraffes; // this is not legal; suppose it were. 
animals.Add(new Tiger()); // it is always legal to put a tiger in a list of animals 

但“动物”实际上是长颈鹿列表;你不能把老虎列入长颈鹿名单。

在C#这是不幸的是,法律参考类型的数组:

Giraffe[] giraffes = new Giraffe[10]; 
Animal[] animals = giraffes; // legal! But dangerous because... 
animals[0] = new Tiger(); // ...this fails at runtime! 

在C#4这是关于IEnumerable的合法的,但不的IList

List<Giraffe> giraffes = new List<Giraffe>(); 
IEnumerable<Animal> animals = giraffes; // Legal in C# 4 
foreach(Animal animal in animals) { } // Every giraffe is an animal, so this is safe 

它是安全,因为IEnumerable<T>不公开任何方法需要在吨T.

解决您的问题,您可以:

  • 创建对象的新列表出来的老名单。
  • 使该方法取对象[]而不是List<object>,并使用不安全的数组协方差。
  • 使该方法通用的,所以它需要一个List<T>
  • 使该方法采取了IEnumerable
  • 使该方法采取IEnumerable<object>并使用C#4
5

您不能投List<OneType>List<OtherType>,因为它实际上是您要投射的列表实例以及列表本身。

有一个扩展方法,这将允许你这样做(MSDN reference):

IEnumerable<Object> myNewEnumerable = myEnumerable.Cast<Object>(); 

此方法将尝试投一个类型的列表中的每个实例的其他类型,并将它们添加到新的enumerable。它会抛出一个异常,如果任何实例不能被转换。

至于系统有关的两种类型的列表只是不同的类型,所以就等于是说:

A objectOfTypeA; 
B objectOfTypeB = (B) objectofTypeA; 

为了能够做演员有必须是一个隐含的或在可用的类型之间进行显式转换,除非你提供了一个,你可能可以做到这一点。

您希望它能够正常工作,因为List<object>将始终能够将任何类型保存在另一个列表中,但是当您用这些术语思考它时,可以看到它的原因。

我敢肯定,有一个技术上更胜一筹的答案,但这是我认为的主旨。

您可能有兴趣阅读Eric Lippert's series on Covariance and Contravariance,这可能对您有好处。

This question也可能是

1

我假定你的意思是,列表是其相互继承或其它方式从一种类型转换为另一种类型的有用的 - 在这种情况下,试试这个:

Tools.MyMethod(MyListOfQuoteHeaders.Cast<OtherType>()); 
-1

的问题是,在编译时,编译器发出2个独立的类,1表示List<MyClass>和一个表示List<Object>。它们基本上是2种不同的类型。至少在.Net中,这就是泛型类型的工作原理。

假设是这样的。网,你可以做

MyListOfQuoteHeaders.Cast<Object>() 

基本上不

var objects = new List<Object>(); 

foreach(var item in MyListOfQuoteHeaders) 
{ 
    objects.Add((object)item); 
} 

return objects; 
+2

这完全不是泛型如何在.NET中工作的。您正在描述如何在C++中使用模板。在.NET中,泛型是作为单一类型发布的,然后在运行时,抖动为每个实例化构造新的代码,并为所有引用类型共享一个实例。 – 2011-05-04 16:37:27

0

感谢许多答复。

我会解释我想做什么以及我想出了什么解决方案。

我需要一种方法,可以通过传入任何类型的对象列表来调用,然后将该列表输出到XML。同样传递给该方法的是一个字符串,它将是一个系统文件结构路径位置,该位置指向XML文件将保存到的位置。由于我有越来越多的类和类型,我想避免编写多种方法来满足每种类型的需求。我不确定我是否以正确的方式走过这条路,但它是解决我的问题和工作的轻量级解决方案。如果有任何问题,或者如果任何人有任何意见,请随时...

所以......我的方法现在看起来像这样...

public static Enums.Status WriteListToXML<T>(string outputPath, List<T> inboundList) 
    { 
     try 
     { 
      XmlSerializer xmlSerializer = new XmlSerializer(inboundList.GetType()); 
      using (StreamWriter streamWriter = System.IO.File.CreateText(outputPath)) 
      { 
       xmlSerializer.Serialize(streamWriter, inboundList); 
      } 
      return Enums.Status.Success; 
     } 
     catch (Exception ex) 
     { 
      return Enums.Status.Failure; 
     } 
    } 

...和我的呼唤行读...

WriteListToXML<QuoteHeader>(@"C:\XMLDocuments\output\QuoteHeaders.xml", quoteHeadersList); 

就像我说的,它可能不是最简洁的解决方案,但它适用于我的情况。

2
List<MyClass> x = someList.Select(f => (MyClass)f).ToList(); 
+2

欢迎来到SO,在这里,解释为什么要使用您的解决方案而不仅仅是一个好的做法。这会让你的答案更有价值,并有助于读者更好地理解你是如何做到的。我还建议你看看我们的FAQ:http://stackoverflow.com/faq。 – ForceMagic 2012-11-10 12:45:16

+0

这是一个非常好的解决方案。但我正在寻找什么。 – Devid 2016-11-29 10:18:27

相关问题