如何将List<object>
投射到List<SomethingElse>
?
(其中SomethingElse
已知来自object
)
Bonus Chatter
投射名单:
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>();
不起作用。
答案 0 :(得分:36)
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查询运算符允许您进一步更改查询的定义。例如,如果您要删除SomethingElse
属性为IsDeleted
的所有true
元素,则可以使用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会将所有运算符存储在查询定义中。然后,当实际枚举序列时(例如,通过foreach
或ToList
),它将为您提供序列的复合结果,并按顺序应用所有查询运算符。
与延迟执行/延迟评估的所有情况一样,请注意不要过度使用此功能。例如,如果你要应用一个Where
运算符来大幅减少序列的大小,那么急切地执行查询并存储枚举列表可能是有意义的。
答案 1 :(得分:17)
我认为你接近Cast<T>
表达式。区别在于Cast<T>
返回IEnumerable<T>
,而不是List<T>
。
试试这个:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
您可以通过执行类似操作来获取列表:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();
答案 2 :(得分:15)
您可以选择使用Cast
或OfType
。如果无法转换为指定的类型,Cast
将抛出异常。另一方面,OfType
将仅返回列表中可以强制转换为指定类型的项目。我建议在你的情况下使用OfType
。
List<Foo> fooList = myList.OfType<Foo>().ToList();