web-dev-qa-db-ja.com

リストとIEnumerableのReverseの2つの完全に異なるバージョンがあるのはなぜですか?

Listオブジェクトには、 Reverse() というメソッドがあります。
リストの順序を「インプレース」と逆にし、何も返しません。

IEnumerableオブジェクトには、 Reverse() という拡張メソッドがあります。
別のIEnumerableを返します。

リスト全体を逆の順序で繰り返す必要があるため、2番目の方法を直接使用することはできません。これは、リストを取得し、それを逆にしたくないので、逆方向に繰り返すだけです。

だから私はこれを行うことができます:

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

または

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

IEnumerableを持っている場合よりも読みにくいことがわかりました。

foreach(var item in list.Reverse())

この2つのメソッドが同じ名前でこのように実装されている理由がわかりません。それはかなり迷惑で混乱します。

すべてのIEnumerableで機能するReverse()の代わりにBackwardsIterator()という拡張機能がないのはなぜですか?

私はこの選択の歴史的な理由に非常に興味があり、「それを行う方法」のものよりも興味があります!

29
Cyril Gandon

Listメソッドはextensionメソッドよりもはるかに古いことに注意してください。 ReverseBackwardsIteratorよりも簡潔に見えるので名前は同じに保たれた可能性があります。

リストバージョンをバイパスして拡張メソッドに移動する場合は、リストをIEnumerable<T>のように扱う必要があります。

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

または、拡張メソッドを静的メソッドとして呼び出します。

Enumerable.Reverse(numbers);

Enumerableバージョンは、逆に反復を開始するために、基になる列挙可能オブジェクトを完全に反復する必要があることに注意してください。同じ列挙型に対してこれを複数回実行することを計画している場合は、順序を永続的に逆にして、通常どおりに繰り返すことを検討してください。

21

その後、独自のBackwardsIteratorを作成してください。

public static IEnumerable BackwardsIterator(this List lst)
{
    for(int i = lst.Count - 1; i >=0; i--)
    {
        yield return lst[i];
    }
}
4
Anirudha

_List<T>.Reverse_の存在は、_IEnumerable<T>.Reverse_の存在よりずっと前に存在していました。それらが同じ名前が付けられている理由は...無能です。それは恐ろしい失敗です。明らかに、Linq _IEnumerable<T>_関数には別の名前を付ける必要があります...例:Backwards ...セマンティクスがまったく異なるため、それがそうであるように、それはプログラマーにとってひどい罠を仕掛けます-誰かがlistのタイプを_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];
}
_
2
Jim Balter