我正在重构我的代码,使用IList代替List。我在几个地方使用了List.RemoveAll,并注意到IList根本没有这个方法。这个做法有什么好的理由吗?
软件工程中有一个原则叫做接口隔离。其核心理念是小接口比大接口更好。当这个想法被推到极致时,理想的接口只声明了一个成员-但我们不需要关心那个。重点是接口应该描述严格的需求而不是方便的特性。
在我们的具体情况中,IList<T>
接口声明了一个类型必须实现的成员才能成为IList<T>
。显然,一个类型并不需要实现RemoveAll
才能成为IList
。这对于一个类型来说是方便的,但不是必须的。
虽然这是扩展方法的一个有效用例。您可以为任何IList<T>
定义自己的RemoveAll
扩展方法,并保持方便。
RemoveAll
可以根据已公开的成员(而不知道其内部)来实现,因此没有理由要求集合为您实现它。 - Theodoros Chatzigiannakis尽管Theodoros Chatzigiannakis解释了一般软件设计的原因,但当您确实需要RemoveAll时(也许您从库中收到了一个IList并希望以更简单的方式进行操作),您可能会感兴趣的解决方案在这里:https://github.com/dotnet/core/issues/2199
根据Dotnet核心团队的答案,我理解主要原因是遗留问题,但正如他们所说,您可以轻松编写扩展方法。这样一个扩展方法的例子(来源: https://www.extensionmethod.net/csharp/icollection-t/removeall)
using System;
using System.Collections.Generic;
using System.Linq;
public static class CollectionExtensions
{
public static void RemoveAll<T>(this ICollection<T> @this, Func<T, bool> predicate)
{
List<T> list = @this as List<T>;
if (list != null)
{
list.RemoveAll(new Predicate<T>(predicate));
}
else
{
List<T> itemsToDelete = @this
.Where(predicate)
.ToList();
foreach (var item in itemsToDelete)
{
@this.Remove(item);
}
}
}
}
IList<T>
接口的类型都应该具有RemoveAll(Predicate<T>)
方法。 - Yuval ItzchakovIList<>
。 - Theodoros Chatzigiannakis