似乎列表对象不能存储在C中的列表变量中,甚至不能以这种方式显式转换。
1 2 3
| List <string> sl = new List <string>();
List <object> ol ;
ol = sl ; |
导致无法隐式地将类型System.Collections.Generic.List转换为System.Collections.Generic.List
然后。。。
1 2 3
| List <string> sl = new List <string>();
List <object> ol ;
ol = (List <object>)sl ; |
导致无法将类型System.Collections.Generic.List转换为System.Collections.Generic.List
当然,您可以通过从字符串列表中提取所有内容并一次将其放回一个列表中来完成,但这是一个相当复杂的解决方案。
- 这将随c 4.0而改变,所以您可能需要查找协方差和反方差。它将以一种类型安全的方式允许这样的事情发生。
- 或多或少重复:stackoverflow.com/questions/317335/&hellip;
- 约翰>C 4不允许这样做。考虑ol.add(new object());
- 乔恩·斯基特回答说:stackoverflow.com/a/2033921/1070906
这样想,如果您要进行这样的转换,然后将foo类型的对象添加到列表中,那么字符串列表就不再一致。如果要迭代第一个引用,则会得到类强制转换异常,因为一旦命中foo实例,就无法将foo转换为字符串!
作为旁注,我认为无论您是否可以进行反向转换,都将更加重要:
1 2 3
| List <object> ol = new List <object>();
List <string> sl ;
sl = (List <string>)ol ; |
我有一段时间没有使用过C,所以我不知道这是否合法,但这种类型的演员表实际上(潜在)是有用的。在本例中,您将从一个更通用的类(对象)转到一个更具体的类(字符串),该类(字符串)从通用类扩展到更具体的类(字符串)。这样,如果您添加到字符串列表中,就不会违反对象列表。
是否有人知道或可以测试这样的演员是否合法?
- 我认为你的例子也有同样的问题。如果ol中有非字符串的内容,会发生什么?问题是列表上的一些方法可以很好地工作,例如添加/插入。但是迭代可能是一个真正的问题。
- 埃里克·利珀特有一系列关于这个主题的博客文章:为什么在通用方法中添加协方差和反方差的矛盾可能有效,但在类级别上可能永远不会像我们希望的那样有效。GD/3KQC
- @克丽萨默曼:如果ol中有一些不是字符串的东西,我想我会期望演员表在运行时失败。但真正会遇到麻烦的是,如果强制转换成功了,然后在ol中添加了一些内容,这不是字符串。因为sl引用了同一个对象,所以现在您的List将包含一个非字符串。问题出在Add上,我想这就是为什么这段代码不能编译的原因,但是如果你把List改为IEnumerable而没有Add的话,它就会编译。(我在C 4检查过这个。)
- 通过这种更改,它编译但抛出一个InvalidCastException,因为ol的运行时类型仍然是List。
如果您使用的是.NET 3.5,请看一下Enumerable.Cast方法。它是一个扩展方法,因此您可以直接在列表中调用它。
1 2 3
| List <string> sl = new List <string>();
IEnumerable <object> ol ;
ol = sl .Cast<object>(); |
这不完全是你想要的,但应该做到这一点。
编辑:正如Zooba所指出的,然后可以调用ol.to list()以获取列表
不能在具有不同类型参数的泛型类型之间强制转换。专门化的泛型类型不构成同一继承树的一部分,因此是不相关的类型。
要执行此3.5版之前的操作:
1 2 3 4 5 6 7 8 9
| 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
} |
使用LINQ:
1 2 3 4 5 6 7 8 9 10
| 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(); |
原因是像List<>这样的通用类在大多数情况下都被外部视为普通类。例如,当你说List()时,编译器说ListString()包含字符串。[技术民谣:这是一个非常简单的英语化版本的正在发生的事情]
因此,显然编译器不够聪明,无法通过强制转换内部集合的项将ListString转换为ListObject。
这就是为什么存在类似于convert()的IEnumerable扩展方法,它允许您轻松地为集合中存储的项提供转换,这与从一个集合到另一个集合的转换一样简单。
这与协方差有很大关系,例如,将泛型类型视为参数,如果参数不能正确解析为更具体的类型,则操作失败。这意味着,您实际上无法强制转换为更一般的类对象类型。如rex所述,list对象不会为您转换每个对象。
您可能希望尝试使用FF代码:
1 2 3
| List <string> sl = new List <string>();
//populate sl
List <object> ol = new List <object>(sl ); |
或:
1 2
| List <object> ol = new List <object>();
ol .AddRange(sl ); |
从理论上讲,ol会毫无问题地复制sl的所有内容。
是的,您可以从.NET 3.5:
1 2
| List <string> sl = new List <string>();
List <object> ol = sl .Cast<object>().ToList(); |
迈克-我相信在C中也不允许有矛盾。
有关更多信息,请参见clr中的泛型类型参数方差。
我认为C 4.0中会支持这一点(相反)。http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
不支持泛型上的此类协方差,但实际上可以对数组执行此操作:
1
| object[] a = new string[] {"spam", "eggs"}; |
C执行运行时检查,以防止将int放入a中。
实际上,这样就不会试图在"ol"列表变量中放入任何奇怪的"object"(如List所允许的那样),因为您的代码会崩溃(因为列表实际上是List并且只接受字符串类型的对象)。这就是为什么不能将变量强制转换为更通用的规范的原因。
在Java上,反过来说,你没有泛型,而在运行时,所有的东西都是对象列表,而且你真的可以在你所谓的严格类型化的列表中填入任何奇怪的对象。搜索"泛化泛型",以查看对Java问题的更广泛的讨论…
1 2 3
| List <string> sl = new List <string>();
List <object> ol ;
ol = new List <object>(sl ); |
嗯,多亏了之前的评论,我找到了两种方法来找到它。第一种方法是获取元素的字符串列表,然后将其转换为IEnumerable对象列表:
1 2 3
| IEnumerable <object> ob ;
List <string> st = new List <string>();
ob = st .Cast<object>(); |
第二种方法是避免IEnumerable对象类型,只需将字符串强制转换为对象类型,然后在同一句话中使用函数"tolist()":
1 2
| List <string> st = new List <string>();
List <object> ob = st .Cast<object>().ToList(); |
我更喜欢第二种方式。我希望这有帮助。
我有一个:
1
| private List <Leerling > Leerlingen = new List <Leerling >(); |
我准备用一个List中收集的数据来填充它。最终对我起作用的是这个:
1
| Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>(); |
.Cast它转换成你想从该类型中得到IEnumerable的类型,然后把IEnemuerable转换成你想要的List<>类型。
对于任何内容可以隐式强制转换的IList,这是另一个.NET 3.5之前的解决方案。
1 2 3 4 5 6 7 8 9 10 11
| public IList ConvertIList <D, B >(IList <D > list ) where D : B
{
List newList = new List ();
foreach (D item in list )
{
newList .Add(item );
}
return newList ;
} |
(基于Zooba的例子)