我在一次采访中被问到这个问题。
假设有一个包含项的 c# 集合,所有这些集合都实现一个包含方法 Update(( 的接口 IUpdatable。如何在单个语句(C#中的一行(中对所有项目调用更新方法?
我确实尝试了收集的foreach,并以这种方式在每个项目上调用update((。采访者说,这更像是初级开发人员的风格。他想要一些简短的东西,在一行中。
我当时没有意识到,但这里有 2 种情况。如果集合尚未属于 collection
我不同意你的面试官的观点,因为一些今天看起来很简单的事情明天会让其他开发人员头疼。
我建议使用List<T>.ForEach
方法
文档 说:
对列表的每个元素执行指定的操作。
即 myList.ForEach(p => myFunc(p));
但它仅适用于 List<T>
,而不是IList<T>
或IEnumerable<T>
所以,如果你的收藏不同,你可以做一个这样的技巧myList.ToList().ForEach(e => ...);
更新
是的,如果需要,您可能希望将项目投射到IUpdatable
即 Enumerable.Cast<T>
或Select(e => (IUpdatable)e)
此外,您可以使用 TPL 和类似Parallel.ForEach
Parallel.ForEach(myList, p =>
{
//Your stuff
});
但我不确定并行执行是否在桌面上
我希望它有所帮助 😊
面试问题的预期答案:
不应使用 LINQ 调用只会产生副作用的方法。所以最好不要那样做。如果需要,List.ForEach
是当你不关心结果时调用方法的惯用方法,但由于我们有一个可能不是列表的集合,它将需要额外的分配(除了强制转换(:
collection.Cast<IUpdatable>().ToList().ForEach(x => x.Update());
要投掷,可以使用Enumerable.Cast<T>
、Enumerable.OfType<T>
或仅使用Select(x => (IUpdatable)x)
。
不太惯用的方法是在常规 LINQ 查询中伪造返回值(如果Update()
有,则忽略一个(。请注意,我们需要以某种方式强制评估查询,例如.ToList()
或更好的.All()
:
collection.Cast<IUpdatable>()
.Select(x => { x.Update(); return true;})
.All(x=>x); // to force evaluation without creating extra list
如果集合已经是类型 IEnumerable<IUpdatable>
(或派生自 IUpdatable
的任何类型(,则不需要Cast
(或OfType
(。
如果这将是创建自定义扩展方法的常见操作,该方法明确设计为每个枚举对象调用操作,那么该方法将比前面显示的两个方法更好。