简体   繁体   English

为什么我不能从列表中投射<myclass>列出<object> ?<div id="text_translate"><p> 我有一个对象列表,它们属于我的QuoteHeader类型,我想将此列表作为对象列表传递给能够接受List&lt;object&gt;的方法。</p><p> 我的代码行显示...</p><pre> Tools.MyMethod((List&lt;object&gt;)MyListOfQuoteHeaders);</pre><p> 但是我在设计时收到以下错误...</p><pre> Cannot convert type 'System.Collections.Generic.List&lt;MyNameSpace.QuoteHeader&gt;' to 'System.Collections.Generic.List&lt;object&gt;'</pre><p> 我需要对我的 class 做任何事情来允许这样做吗? 我认为所有类都继承自 object 所以我不明白为什么这不起作用?</p></div></object></myclass>

[英]Why can't I cast from a List<MyClass> to List<object>?

I have a List of objects, which are of my type QuoteHeader and I want to pass this list as a list of objects to a method which is able to accept a List<object> .我有一个对象列表,它们属于我的QuoteHeader类型,我想将此列表作为对象列表传递给能够接受List<object>的方法。

My line of code reads...我的代码行显示...

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

But I get the following error at design time...但是我在设计时收到以下错误...

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

Do I need to do anything to my class to allow this?我需要对我的 class 做任何事情来允许这样做吗? I thought that all classes inherit from object so I can't understand why this wouldn't work?我认为所有类都继承自 object 所以我不明白为什么这不起作用?

The reason this is not legal is because it is not safe.这不合法的原因是因为它不安全。 Suppose it were legal:假设它是合法的:

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

But "animals" is actually a list of giraffes;但“动物”实际上是长颈鹿的列表; you can't put a tiger in a list of giraffes.你不能把老虎放在长颈鹿的名单上。

In C# this is, unfortunately, legal with arrays of reference type:不幸的是,在 C# 中,这对于引用类型的 arrays 是合法的:

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

In C# 4 this is legal on IEnumerable but not IList :在 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

It is safe because IEnumerable<T> does not expose any method that takes in a T.这是安全的,因为IEnumerable<T>不公开任何接受T 的方法。

To solve your problem you can:要解决您的问题,您可以:

  • Create a new list of objects out of the old list.从旧列表中创建一个新的对象列表。
  • Make the method take an object[] rather than a List<object> , and use unsafe array covariance.使该方法采用 object[] 而不是List<object> ,并使用不安全的数组协方差。
  • Make the method generic, so it takes a List<T>使方法通用,所以它需要一个List<T>
  • Make the method take IEnumerable使方法采用 IEnumerable
  • Make the method take IEnumerable<object> and use C# 4.使方法采用IEnumerable<object>并使用 C# 4。

You can't cast List<OneType> to List<OtherType> as it is actually the instances of the list you want to cast, as well as the List itself.您不能将List<OneType>转换为List<OtherType>因为它实际上是您要转换的列表的实例,以及 List 本身。

there is an extension method which will allow you to do this ( MSDN reference ):有一种扩展方法可以让您执行此操作( MSDN 参考):

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

This method will attempt to cast each instance of the list of one type to the other type and add them to a new enumerable.此方法将尝试将一种类型列表的每个实例转换为另一种类型,并将它们添加到新的可枚举中。 it will throw an exception if any instance can't be cast.如果无法转换任何实例,它将引发异常。

As far as the system is concerned the two types for your lists are just different types, so it is like saying:就系统而言,您的列表的两种类型只是不同的类型,所以就像说:

A objectOfTypeA;
B objectOfTypeB = (B) objectofTypeA;

To be able to do the cast there would have to be an implicit or explicit conversion between the types available, which there isn't (unless you provided one, which you might be able to do).为了能够进行强制转换,必须在可用类型之间进行隐式或显式转换,而这是不存在的(除非您提供了一个,您可能可以这样做)。

you expect it to work because List<object> will always be able to hold any type in another list, but when you think about it in those terms you can see why it doesn't.您希望它能够工作,因为List<object>将始终能够在另一个列表中保存任何类型,但是当您以这些术语考虑它时,您会明白为什么它不能。

I'm sure there is a more technically competent answer, but that is the gist of it I think.我确信有一个技术上更胜任的答案,但我认为这就是它的要点。

you might be interested in reading Eric Lippert's series on Covariance and Contravariance as this may be helpful to you.您可能有兴趣阅读Eric Lippert 关于协变和逆变的系列文章,因为这可能对您有所帮助。

This question may also be useful这个问题也可能有用

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

I'm presuming that you mean that the lists are of types which inherit from each other or can otherwise be cast from one type to another - in that case, try this:我假设您的意思是列表是相互继承的类型,或者可以从一种类型转换为另一种类型 - 在这种情况下,试试这个:

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

Thanks for the many responses.感谢您的许多回复。

I'll explain what I wanted to do and what I've come up with as a solution.我将解释我想做什么以及我想出的解决方案。

I needed a method that I could call by passing in a List of objects of any type and then output that list to XML.我需要一个方法,我可以通过传入任何类型的对象列表然后将 output 传递给 XML 来调用该方法。 Also passed to the method would be a string which would be a system file structure path location which points to the location the XML file would be saved to.传递给该方法的还有一个字符串,它将是一个系统文件结构路径位置,它指向 XML 文件将保存到的位置。 As I have an ever growing number of classes and types, I wanted to avoid writing multiple methods to cater for each type of class.由于我有越来越多的类和类型,我想避免编写多种方法来满足每种类型的 class。 I'm not sure if I've even gone about this the right way, but it's a lightweight solution to my problem and works.我不确定我是否以正确的方式解决了这个问题,但它是解决我的问题并且有效的轻量级解决方案。 If there are any issues with it, or if anyone has any comments please feel free...如果有任何问题,或者如果任何人有任何意见,请随时...

So... my method now looks like this...所以......我的方法现在看起来像这样......

    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;
        }
    }

... and my calling line reads... ...而我的电话号码是...

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

Like I said, it may not be the tidiest solution, but it works well in my scenario.就像我说的,它可能不是最整洁的解决方案,但在我的场景中效果很好。

The problem is that at Compile time, the compiler emits 2 separate classes, 1 that represents List<MyClass> and one that represents List<Object> .问题是在编译时,编译器发出 2 个单独的类,1 个代表List<MyClass> ,一个代表List<Object> They are essentially 2 separate types.它们本质上是两种不同的类型。 That's how Generic types work, in.Net at least.这就是通用类型的工作方式,至少在.Net 中是这样。

Assuming this is.Net, you could do假设这是.Net,你可以做

MyListOfQuoteHeaders.Cast<Object>()

which basically does基本上可以

var objects = new List<Object>();

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

return objects;

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

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