如何将List<object>转换为List<SomethingElse>?

72

如何将List<object>强制转换为List<SomethingElse>

(其中SomethingElse已知是从object继承而来)


额外的闲聊

转换列表:

List<Object> first = ...;

List<SomethingElse> second = (List<SomethingElse>)first;

无法转换类型'System.Collections.Generic.List'为'System.Collections.Generic.List'

尝试进行列表强制类型转换:

List<SomethingElse> second = first.Cast<SomethingElse>();

无法隐式转换类型'System.Collections.Generic.List'为'System.Collections.Generic.List'

不起作用:

我实际上并不需要完整的List<T>对象,只需要一个ICollection<T>即可:

ICollection<SomethingElse> second = first;
ICollection<SomethingElse> second = (ICollection<SomethingElse>)first;
ICollection<SomethingElse> second = first.Cast<SomethingElse>();

不起作用。


相关的吗?https://dev59.com/HnM_5IYBdhLWcg3wslfs - eldarerathis
可能是https://dev59.com/GGsz5IYBdhLWcg3wWmfL的重复问题。 - dash
这样行吗?List<SomethingElse> second = first.Select(o => (SomethingElse)o).ToList(); - user356178
3个回答

53

LINQ通过Enumerable类内的扩展方法实现,依赖于延迟执行:

在返回一系列值的查询中使用的方法在枚举查询对象之前不会消耗目标数据。这被称为延迟执行。

Cast<T>不会立即创建新列表,而是存储执行操作所需的所有信息。该列表只会在需要时(例如通过foreach语句)被枚举。

在您的情况下,如果您只是想遍历序列,则应考虑使用IEnumerable<T>接口,它是Cast<T>的声明返回类型:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
foreach (SomethingElse se in second)
{
    // ...
}

这是高效的,因为它只在迭代每个项目时执行转换。

如果你确信想要立即创建一个新列表,请使用ToList

List<SomethingElse> second = first.Cast<SomethingElse>().ToList();

编辑: 回复评论中的观点:

这取决于你所说的“可修改的列表”是什么意思。有几个LINQ查询运算符可以让你进一步修改查询的定义。例如,如果你想删除所有IsDeleted属性为trueSomethingElse元素,你可以使用Where运算符:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
second = second.Where(element => !element.IsDeleted);

如果您想添加一系列的新元素,可以使用Concat运算符:

second = second.Concat(anotherCollectionOfSomethingElse);

如果你想按升序排序你的序列中的ID,使用OrderBy运算符:

second = second.OrderBy(element => element.ID);
每次,我们都会在查询的前一个定义上应用一个查询运算符,并将新的(复合)查询分配给我们的second变量。LINQ将在查询定义中存储所有运算符。然后,当序列实际枚举时(例如通过foreachToList),它将按顺序应用所有查询运算符,给出您序列的复合结果。
与所有延迟执行/惰性求值的情况一样,要小心不要过度使用。例如,如果您将应用一个Where运算符,它将大大减少您的序列大小,那么立即执行查询并存储枚举列表可能是有意义的。

我不需要立即创建一个新列表;但我需要一个可以修改的列表,并且不受协变问题的限制。如果 ToList 是我需要的,那么我需要使用它。当然,我希望返回的 List 是围绕 first 的包装器,也允许延迟执行。 - Ian Boyd

29

你可以选择使用CastOfType。如果无法转换为指定类型,Cast将抛出异常。另一方面,OfType将仅返回列表中可以转换为指定类型的项。在您的情况下,我建议使用OfType

List<Foo> fooList = myList.OfType<Foo>().ToList();

23

我认为你在使用Cast<T>表达式上已经接近正确了。不同之处是Cast<T>返回的是一个IEnumerable<T>而不是List<T>

尝试这样做:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
你可以通过类似的方法获取一个列表:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接