在C#中,为什么List <string>对象不能存储在List <object>variables中
看来List对象不能存储在C#中的Listvariables中,甚至不能以这种方式显式地转换。
List<string> sl = new List<string>(); List<object> ol; ol = sl;
结果不能将typesSystem.Collections.Generic.List<string>
隐式转换为System.Collections.Generic.List<object>
接着…
List<string> sl = new List<string>(); List<object> ol; ol = (List<object>)sl;
结果无法将typesSystem.Collections.Generic.List<string>
转换为System.Collections.Generic.List<object>
当然,你可以把所有的东西都从string列表中拉出来放回去,但这是一个相当复杂的解决scheme。
想想这样,如果你要做这样的转换,然后将一个Footypes的对象添加到列表中,则string列表不再一致。 如果您要迭代第一个引用,则会得到类转换exception,因为一旦您点击Foo实例,Foo就无法转换为string!
作为一个方面说明,我认为你是否可以做反向演员会更有意义:
List<object> ol = new List<object>(); List<string> sl; sl = (List<string>)ol;
我有一段时间没有使用C#,所以我不知道这是否合法,但是这种types的转换实际上是(可能)有用的。 在这种情况下,你将从一个更普通的类(对象)转向更具体的类(string),从一般类inheritance。 这样,如果添加到string列表中,则不违反对象列表。
有人知道或可以testing,如果这样的演员在C#合法吗?
如果您使用.NET 3.5,请查看Enumerable.Cast方法。 这是一个扩展方法,所以你可以直接在列表中调用它。
List<string> sl = new List<string>(); IEnumerable<object> ol; ol = sl.Cast<object>();
这不完全是你要求的,但应该做的伎俩。
编辑:如Zooba所指出的,你可以调用ol.ToList()来获得一个List
您不能在具有不同types参数的genericstypes之间进行转换。 专门的genericstypes不构成同一inheritance树的一部分,因此是不相关的types。
要做到这一点,NET-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 }
使用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();
原因在于像List<>
这样的generics类在大多数情况下被作为一个普通的类来处理。 例如当你说List<string>()
,编译器会说ListString()
(它包含string)。 [技术人员:这是一个非常简单的英语版本]
因此,显然编译器不能够通过强制转换其内部集合的项目来将ListString转换为ListObject。
这就是为什么像Convert()这样的IEnumerable的扩展方法,它允许您轻松地为存储在集合中的项目提供转换,这可以像从一个铸造到另一个一样简单。
这与协方差有很大关系,例如,generics被视为参数,如果参数不能正确parsing为更具体的types,则操作失败。 这样的含义是,你不能像对象那样投射到一个更普通的types。 正如雷克斯所说,List对象不会为你转换每个对象。
你可能想尝试一下ff代码:
List<string> sl = new List<string>(); //populate sl List<object> ol = new List<object>(sl);
要么:
List<object> ol = new List<object>(); ol.AddRange(sl);
ol(理论上)将sl的所有内容都没有问题地复制。
是的,你可以从.NET 3.5:
List<string> sl = new List<string>(); List<object> ol = sl.Cast<object>().ToList();
迈克 – 我相信在C#中反对也是不允许的
有关更多信息,请参阅CLR中的genericstypes参数差异 。
我认为这个(反变换)实际上将在C#4.0中得到支持。 http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
这实际上是因为你不会尝试在你的“ol”列表变体(就像List<object>
似乎允许的那样)中放置任何奇怪的“对象”,因为你的代码会崩溃(因为列表真的是List<string>
,只会接受Stringtypes的对象)。 这就是为什么你不能把你的variables转换成更一般的规范。
在Java上反过来,你没有generics,而是在运行时对象列表,而你真的可以在你所谓的严格types的List中填充任何奇怪的对象。 search“泛化的generics”来查看java的问题的更广泛的讨论…
这种generics的协变是不支持的,但你可以用数组来实现:
object[] a = new string[] {"spam", "eggs"};
C#执行运行时检查,以防止你把一个int
放入a
。
这里是另一个可以隐式转换内容的IList的.NET 3.5解决scheme。
public IList<B> ConvertIList<D, B>(IList<D> list) where D : B { List<B> newList = new List<B>(); foreach (D item in list) { newList.Add(item); } return newList; }
(基于Zooba的例子)
我有一个:
private List<Leerling> Leerlingen = new List<Leerling>();
而且我要用在List<object>
收集的数据来填充它。最后为我工作的是这个:
Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();
.Cast
它传递给你想从这个types获得一个IEnumerable
types,然后将IEnemuerable
types转换为你想要的List<>
。
恩,感谢之前的评论,我find了两种方法找出来。 第一个是获取元素的string列表,然后将其转换为IEnumerable对象列表:
IEnumerable<object> ob; List<string> st = new List<string>(); ob = st.Cast<object>();
第二个是避免IEnumerable对象types,只是将string强制转换为对象types,然后在同一个语句中使用函数“toList()”:
List<string> st = new List<string>(); List<object> ob = st.Cast<object>().ToList();
我更喜欢第二种方式。 我希望这有帮助。
List<string> sl = new List<string>(); List<object> ol; ol = new List<object>(sl);