34

对于List对象,我们有一个名为Reverse()的方法。
它颠倒了“就地”列表的顺序,它不返回任何东西。

对于该对象,我们有一个名为Reverse()IEnumerable的扩展方法。 它返回另一个 IEnumerable。

我需要以相反的顺序遍历一个列表,所以我不能直接使用第二种方法,因为我得到一个列表,我不想反转它,只是向后迭代。

所以我可以这样做:

for(int i = list.Count - 1; i >=0; i--)

或者

foreach(var item in list.AsEnumerable().Reverse())

我发现它比如果我有一个 IEnumerable 可读性差,就这样做

foreach(var item in list.Reverse())

我不明白为什么这两种方法以这种方式实现,名称相同。这很烦人和令人困惑。

为什么没有一个名为 BackwardsIterator() 的扩展来代替适用于所有 IEnumerable 的 Reverse()?

我对这个选择的历史原因非常感兴趣,而不是“如何做”的东西!

4

3 回答 3

27

值得注意的是,列表方法比扩展方法要老很多。命名可能保持不变,Reverse似乎比BackwardsIterator.

如果您想绕过列表版本并转到扩展方法,则需要将列表视为IEnumerable<T>

var numbers = new List<int>();
numbers.Reverse(); // hits list
(numbers as IEnumerable<int>).Reverse(); // hits extension

或者将扩展方法作为静态方法调用:

Enumerable.Reverse(numbers);

请注意,该Enumerable版本将需要完全迭代底层可枚举,以便开始反向迭代它。如果您打算对同一个可枚举项多次执行此操作,请考虑永久颠倒顺序并正常迭代。

于 2012-09-12T14:57:26.040 回答
5

那就写你自己的 BackwardsIterator 吧!

public static IEnumerable BackwardsIterator(this List lst)
{
    for(int i = lst.Count - 1; i >=0; i--)
    {
        yield return lst[i];
    }
}
于 2012-09-12T14:57:34.113 回答
2

存在List<T>.Reverse早于存在IEnumerable<T>.Reverse。他们被命名相同的原因是......无能。这是一个可怕的烂摊子;显然,LinqIEnumerable<T>函数应该被赋予一个不同的名称……例如,Backwards……因为它们具有完全不同的语义。事实上,它为程序员设置了一个可怕的陷阱——有人可能将listfrom的类型更改List<T>为,例如 ,Collection<T>然后突然 list.Reverse();,而不是原地反转list,只是返回一个IEnumerable<T>被丢弃的。不能夸大 MS 给这些方法取同名的能力是多么的无能。

为避免该问题,您可以定义自己的扩展方法

public static IEnumerable<T> Backwards<T>(this IEnumerable<T> source) => source.Reverse();

您甚至可以添加一个特殊情况来高效处理可索引列表:

public static IEnumerable<T> Backwards<T>(this IEnumerable<T> source) =>
    source is IList<T> list ? Backwards<T>(list) : source.Reverse();

public static IEnumerable<T> Backwards<T>(this IList<T> list)
{
    for (int x = list.Count; --x >= 0;)
        yield return list[x];
}
于 2018-11-24T08:33:54.283 回答