为什么我不能从列表转换为列表?

时间:2021-12-15 19:42:16

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的方法。

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? I thought that all classes inherit from object so I can't understand why this wouldn't work?

我需要对我的班级做些什么来允许这个吗?我以为所有的类都是从object继承的所以我不明白为什么它不能工作?

6 个解决方案

#1


31  

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#中,这是一种合法的引用类型数组:

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的方法。

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.
  • 让方法使用对象[]而不是List,并使用不安全的数组协方差。
  • Make the method generic, so it takes a List<T>
  • 使该方法具有通用性,所以它需要一个列表
  • Make the method take IEnumerable
  • 让这个方法取IEnumerable。
  • Make the method take IEnumerable<object> and use C# 4.
  • 使该方法使用IEnumerable,使用c# 4。

#2


5  

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 列到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将始终能够在另一个列表中保存任何类型,但是当您以这些术语考虑它时,您可以看到为什么它不能保存。

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

这个问题也可能有用

#3


3  

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

#4


1  

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>());

#5


0  

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. 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. 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. 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...

我需要一个方法,我可以通过传入任何类型的对象列表并将该列表输出到XML来调用它。传递给方法的还有一个字符串,它是一个系统文件结构路径位置,指向XML文件将被保存到的位置。由于类和类型的数量不断增加,我希望避免为满足每种类型的类编写多个方法。我不确定我是否采用了正确的方法,但这是一个轻量级的解决方案,可以解决我的问题并有效地工作。如果有任何问题,或任何人有任何意见,请放心…

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.

就像我说的,它可能不是最方便的解决方案,但在我的方案中效果很好。

#6


-1  

The problem is that at Compile time, the compiler emits 2 separate classes, 1 that represents List<MyClass> and one that represents List<Object>. They are essentially 2 separate types. That's how Generic types work, in .Net at least.

问题是,在编译时,编译器发出两个单独的类,一个表示List ,另一个表示List 。它们本质上是两种不同的类型。至少在。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;

#1


31  

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#中,这是一种合法的引用类型数组:

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的方法。

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.
  • 让方法使用对象[]而不是List,并使用不安全的数组协方差。
  • Make the method generic, so it takes a List<T>
  • 使该方法具有通用性,所以它需要一个列表
  • Make the method take IEnumerable
  • 让这个方法取IEnumerable。
  • Make the method take IEnumerable<object> and use C# 4.
  • 使该方法使用IEnumerable,使用c# 4。

#2


5  

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 列到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将始终能够在另一个列表中保存任何类型,但是当您以这些术语考虑它时,您可以看到为什么它不能保存。

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

这个问题也可能有用

#3


3  

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

#4


1  

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>());

#5


0  

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. 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. 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. 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...

我需要一个方法,我可以通过传入任何类型的对象列表并将该列表输出到XML来调用它。传递给方法的还有一个字符串,它是一个系统文件结构路径位置,指向XML文件将被保存到的位置。由于类和类型的数量不断增加,我希望避免为满足每种类型的类编写多个方法。我不确定我是否采用了正确的方法,但这是一个轻量级的解决方案,可以解决我的问题并有效地工作。如果有任何问题,或任何人有任何意见,请放心…

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.

就像我说的,它可能不是最方便的解决方案,但在我的方案中效果很好。

#6


-1  

The problem is that at Compile time, the compiler emits 2 separate classes, 1 that represents List<MyClass> and one that represents List<Object>. They are essentially 2 separate types. That's how Generic types work, in .Net at least.

问题是,在编译时,编译器发出两个单独的类,一个表示List ,另一个表示List 。它们本质上是两种不同的类型。至少在。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;