在 C# 中,为什么不能将 List<string> 对象存储在 List<object> 变量中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C#, why can't a List<string> object be stored in a List<object> variable
提问by Matt Sheppard
It seems that a List object cannot be stored in a List variable in C#, and can't even be explicitly cast that way.
似乎 List 对象不能存储在 C# 中的 List 变量中,甚至不能以这种方式显式转换。
List<string> sl = new List<string>();
List<object> ol;
ol = sl;
results in Cannot implicitly convert type System.Collections.Generic.List<string>
to System.Collections.Generic.List<object>
导致无法将类型隐式转换System.Collections.Generic.List<string>
为System.Collections.Generic.List<object>
And then...
进而...
List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;
results in Cannot convert type System.Collections.Generic.List<string>
to System.Collections.Generic.List<object>
导致无法将类型转换System.Collections.Generic.List<string>
为System.Collections.Generic.List<object>
Of course, you can do it by pulling everything out of the string list and putting it back in one at a time, but it is a rather convoluted solution.
当然,您可以通过从字符串列表中取出所有内容并一次将其放回一个来实现,但这是一个相当复杂的解决方案。
采纳答案by Mike Stone
Think of it this way, if you were to do such a cast, and then add an object of type Foo to the list, the list of strings is no longer consistent. If you were to iterate the first reference, you would get a class cast exception because once you hit the Foo instance, the Foo could not be converted to string!
可以这样想,如果您要进行这样的转换,然后将 Foo 类型的对象添加到列表中,则字符串列表不再一致。如果你要迭代第一个引用,你会得到一个类转换异常,因为一旦你命中 Foo 实例,Foo 就不能转换为字符串!
As a side note, I think it would be more significant whether or not you can do the reverse cast:
作为旁注,我认为您是否可以进行反向转换会更重要:
List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;
I haven't used C# in a while, so I don't know if that is legal, but that sort of cast is actually (potentially) useful. In this case, you are going from a more general class (object) to a more specific class (string) that extends from the general one. In this way, if you add to the list of strings, you are not violating the list of objects.
我有一段时间没有使用 C#,所以我不知道这是否合法,但这种类型的转换实际上(可能)有用。在这种情况下,您将从更通用的类(对象)转换为从通用类扩展的更具体的类(字符串)。这样,如果您添加到字符串列表中,就不会违反对象列表。
Does anybody know or can test if such a cast is legal in C#?
有人知道或可以测试这样的强制转换在 C# 中是否合法吗?
回答by Rex M
The reason is that a generic class like List<>
is, for most purposes, treated externally as a normal class. e.g. when you say List<string>()
the compiler says ListString()
(which contains strings). [Technical folk: this is an extremely plain-English-ified version of what's going on]
原因是List<>
,在大多数情况下,像这样的泛型类在外部被视为普通类。例如,当您说List<string>()
编译器说ListString()
(其中包含字符串)时。[技术人员:这是正在发生的事情的非常简单的英语版本]
Consequently, obviously the compiler can't be smart enough to convert a ListString to a ListObject by casting the items of its internal collection.
因此,显然编译器不够聪明,无法通过转换其内部集合的项目将 ListString 转换为 ListObject。
That's why there's extension methods for IEnumerable like Convert() that allow you to easily supply conversion for the items stored inside a collection, which could be as simple as casting from one to another.
这就是为什么有像 Convert() 这样的 IEnumerable 扩展方法,它允许您轻松地为存储在集合中的项目提供转换,这可能就像从一个转换到另一个一样简单。
回答by Matt Sheppard
Mike - I believe contravariance isn't allowed in C# either
Mike - 我相信 C# 中也不允许逆变
See Generic type parameter variance in the CLRfor some more info.
有关更多信息,请参阅CLR 中的通用类型参数变化。
回答by Jon Limjap
This has a lot to do with covariance, e.g., generic types are considered as parameters, and if the parameters do not resolve properly to a more specific type then the operation fails. The implication of such is that you really cannot cast to a more general type like object. And as stated by Rex, the List object won't convert each object for you.
这与协方差有很大关系,例如,泛型类型被视为参数,如果参数不能正确解析为更具体的类型,则操作失败。这意味着您确实无法转换为更通用的类型,例如 object。正如 Rex 所说,List 对象不会为您转换每个对象。
You might want to try the ff code instead:
您可能想尝试使用 ff 代码:
List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);
or:
或者:
List<object> ol = new List<object>();
ol.AddRange(sl);
ol will (theoretically) copy all the contents of sl without problems.
ol 将(理论上)复制 sl 的所有内容而不会出现问题。
回答by Ray
If you're using .NET 3.5 have a look at the Enumerable.Cast method. It's an extension method so you can call it directly on the List.
如果您使用的是 .NET 3.5,请查看 Enumerable.Cast 方法。它是一个扩展方法,因此您可以直接在 List 上调用它。
List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();
It's not exactly what you asked for but should do the trick.
这不完全是您所要求的,但应该可以解决问题。
Edit: As noted by Zooba, you can then call ol.ToList() to get a List
编辑:正如 Zooba 所指出的,然后您可以调用 ol.ToList() 来获取列表
回答by Zooba
You cannot cast between generic types with different type parameters. Specialized generic types don't form part of the same inheritance tree and so are unrelated types.
您不能在具有不同类型参数的泛型类型之间进行转换。专用泛型类型不构成同一继承树的一部分,因此是不相关的类型。
To do this pre-NET 3.5:
要在 NET 3.5 之前执行此操作:
List<string> sl = new List<string>();
// Add strings to sl
List<object> ol = new List<object>();
foreach(string s in sl)
{
ol.Add((object)s); // The cast is performed implicitly even if omitted
}
Using Linq:
使用 Linq:
var sl = new List<string>();
// Add strings to sl
var ol = new List<object>(sl.Cast<object>());
// OR
var ol = sl.Cast<object>().ToList();
// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();
回答by Valters Vingolds
That's actually so that you don't try to put any odd "object" in your "ol" list variant (as List<object>
would seem to allow) - because your code would crash then (because the list really is List<string>
and will only accept String type objects). That's why you can't cast your variable to a more general specification.
这实际上是为了让您不要尝试在“ol”列表变体中放置任何奇怪的“对象”(List<object>
似乎允许) - 因为您的代码会崩溃(因为列表确实List<string>
并且只会接受 String 类型的对象)。这就是为什么您不能将变量转换为更通用的规范。
On Java it's the other way around, you don't have generics, and instead everything is List of object at runtime, and you really can stuff any strange object in your supposedly-strictly typed List. Search for "Reified generics" to see a wider discussion of java's problem...
在 Java 上,情况正好相反,你没有泛型,而是在运行时一切都是对象列表,你真的可以在你所谓的严格类型列表中填充任何奇怪的对象。搜索“Reified generics”以查看对 java 问题的更广泛讨论......
回答by Constantin
Such covariance on generics is not supported, but you can actually do this with arrays:
不支持泛型的这种协方差,但您实际上可以使用数组来做到这一点:
object[] a = new string[] {"spam", "eggs"};
C# performs runtime checks to prevent you from putting, say, an int
into a
.
C#执行运行时检查,以防止你把,比如说,一个int
进a
。
回答by Tamas Czinege
Yes, you can, from .NET 3.5:
是的,您可以从 .NET 3.5 开始:
List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();
回答by MattValerio
I think that this (contravariance) will actually be supported in C# 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
我认为 C# 4.0 实际上会支持这个(逆变)。 http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx