为什么Reverse for List和IEnumerable有两个完全不同的版本?
对于List
对象,我们有一个名为Reverse()的方法。
它反转了“就地”列表的顺序,它不会返回任何内容。
对于IEnumerable
对象,我们有一个名为Reverse()的扩展方法。
它返回另一个IEnumerable。
我需要以相反的顺序遍历列表,所以我不能直接使用第二种方法,因为我得到一个List,我不想反转它,只是向后迭代。
所以我可以这样做:
for(int i = list.Count - 1; i >=0; i--)
要么
foreach(var item in list.AsEnumerable().Reverse())
我发现它的可读性低于我拥有IEnumerable时的可读性
foreach(var item in list.Reverse())
我无法理解为什么这两种方法以这种方式实现,名称相同。 这很令人讨厌和困惑。
为什么在Reverse()中没有一个名为BackwardsIterator()的扩展名为所有IEnumerable工作?
我对这种选择的历史原因非常感兴趣,而不是“怎么做”的东西!
值得注意的是,list方法比扩展方法要老很多。 命名可能保持不变,因为Reverse
似乎比BackwardsIterator
更简洁。
如果要绕过列表版本并转到扩展方法,则需要将列表视为IEnumerable
:
var numbers = new List(); numbers.Reverse(); // hits list (numbers as IEnumerable ).Reverse(); // hits extension
或者将扩展方法称为静态方法:
Enumerable.Reverse(numbers);
请注意, Enumerable
版本需要完全迭代底层枚举,以便开始反向迭代。 如果您打算在同一个可枚举项上多次执行此操作,请考虑永久性地颠倒顺序并正常迭代它。
然后编写自己的BackwardsIterator!
public static IEnumerable BackwardsIterator(this List lst) { for(int i = lst.Count - 1; i >=0; i--) { yield return lst[i]; } }
不同之处在于List
是一个类而IEnumerable
是一个接口。 这意味着List对象有一个实现(好吧,它是一个实现),并且Reverse
的效果保证存储在对象的内部状态中。
使用IEnumerable
它是不同的:任何对象都可以实现它,而没有义务实现Reverse
方法,因为它不是接口的一部分。 Reverse()
扩展方法只能以相反的顺序枚举IEnumerable
的枚举IEnumerable
,但永远不会改变主体的内部状态。
但是当Enumerable
及其扩展方法被引入时, List.Reverse
已经存在。 如果它们是同时发明的, List.Reverse
也可能是一种无状态的方法,为了统一性。 谁知道。