1

タイトルは質問をほぼ要約しています。私はそれに何の問題もありません。そのデザインの選択の背後にある理由に興味があるだけです.

4

3 に答える 3

1

私の推測?さまざまなプロバイダーに対するシンプルさと互換性。

他のいくつかの回答とは対照的に、これは遅延実行とは関係ありません。これは重要な概念ですが、問題とは無関係です。たとえば、次の完全に有効なメソッドを作成できます。

public static IEnumerable<T> NotBuffered<T>(this IEnumerable<T> input) 
{
    return (IEnumerable<T>)input.ToList();  //not deferred
}

WhereEnumerableまたは、 aと同じように機能するIEnumerableが、次のプロパティを持つa を公開することもできます。

WhereEnumerable data = source.Where(x=> x.Name == "Cheese"); //still deferred
print(data.First());
print(data.skipped); //Number of items that failed the test.
print(data.returned); //Number of items that passed the test.

そして、これはおそらく有用であり、実証されているように、基本的なLinqToObjects実装で簡単に実装できます。ただし、 LinqToSQL 、 LinqToMongo、またはLinqToOpenCLドライバーで同じ機能を実装することは、かなり難しいか不可能かもしれません。これにより、実装間でのコードの移植性が低下し、実装者の複雑さが増します。

たとえば、MongoDB はサーバー上で (特殊なクエリ言語で) クエリを実行し、これらの統計をユーザーが利用できるようにしません。さらに、インデックスなどの概念を使用すると、これらの概念は無意味になる可能性があります。たとえばusers.Where(user => user.ID = "{ID"}).First()、インデックスでは、結果を見つける前に 0 レコードを「スキップ」する可能性があります。インデックス内の 100,412 またはディスクまたはインデックス ノード 431 の 40,231 の位置にある場合でも、それは 'シンプルな問題...

最後に、必要に応じて独自の LINQ メソッドを記述して、この機能を使用して独自のカスタム型を返すか、「統計」オブジェクトなどを出力するオーバーロードを介していつでも作成できます。後者の架空の例:

var stats = new WhereStats();
WhereEnumerable data = source.Where(x=> x.Name == "Cheese", stats);
print(data.First());
print(stats.skipped); //Number of items that failed the test.
print(stats.returned); //Number of items that passed the test.

編集: 入力された where の例 (概念実証のみ):

using System;
using System.Collections.Generic;
using System.Linq;

namespace TypedWhereExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = Enumerable.Range(0, 1000);
            var typedWhere1 = data.TypedWhere(x => x % 2 == 0);
            var typedWhere2 = typedWhere1.TypedWhere(x => x % 3 == 0);
            var result = typedWhere2.Take(10).ToList();  //Works like usual Linq

            //But returns additional data
            Console.WriteLine("Result: " + string.Join(",", result));
            Console.WriteLine("Typed Where 1 Skipped: " + typedWhere1.Skipped);
            Console.WriteLine("Typed Where 1 Returned: " + typedWhere1.Returned);
            Console.WriteLine("Typed Where 2 Skipped: " + typedWhere2.Skipped);
            Console.WriteLine("Typed Where 2 Returned: " + typedWhere2.Returned);
            Console.ReadLine();

            //Result: 0,6,12,18,24,30,36,42,48,54
            //Typed Where 1 Skipped: 27
            //Typed Where 1 Returned: 28
            //Typed Where 2 Skipped: 18
            //Typed Where 2 Returned: 10
        }
    }

    public static class MyLINQ
    {
        public static TypedWhereEnumerable<T> TypedWhere<T>
            (this IEnumerable<T> source, Func<T, bool> filter)
        {
            return new TypedWhereEnumerable<T>(source, filter);
        }
    }

    public class TypedWhereEnumerable<T> : IEnumerable<T>
    {
        IEnumerable<T> source;
        Func<T, bool> filter;

        public int Skipped { get; private set; }
        public int Returned { get; private set; }

        public TypedWhereEnumerable(IEnumerable<T> source, Func<T, bool> filter)
        {
            this.source = source;
            this.filter = filter;
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            foreach (var o in source)
                if (filter(o)) { Returned++; yield return o; }
                else Skipped++;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            foreach (var o in source)
                if (filter(o)) { Returned++; yield return o; }
                else Skipped++;
        }
    }
}
于 2013-11-06T10:07:11.747 に答える
-1

あなたの質問を正しく理解できるようにするために、例を使用します。

この方法を取ります:

public static IEnumerable<TSource> Where<TSource>
    (this IEnumerable<TSource> source, Func<TSource, bool> predicate)

あなたの質問は次のとおりだと思います。IEnumerable<TSource>たとえば、返されないのはなぜEnumerable.WhereEnumerableIterator<TSource>ですか?

上記の型は、返されるオブジェクトの実際の実行時型ですが、メソッドは単純にそれを と宣言していることに注意してIEnumerable<TSource>ください。

答えは、それ以外の方法では実質的に何のメリットもありませんが、ゼロではないコストが発生するということです。費用が利益よりも高い場合は、それを行わないでください。

メリットがないのはなぜ?

まず第一に、WhereEnumerableIterator<TSource>まだ静的に型付けされている多くのオブジェクトがあるためIEnumerable<TSource>です。その結果、メソッドのオーバーロードは機能せず、現在と同じように、Where メソッドは、シーケンスWhereEnumerableIterator<TSource>を最適化する場合、その入力を a にキャストしようとする必要があります。.Where(...).Where(...)これにはいくつかの理由がありますが、そのうちの 1 つが次のパターンです。

IEnumerable<whatever> q = source;

if (!string.IsNullOrEmpty(searchText))
{
    q = q.Where(item => item.Name.Contains(searchText));
}

if (startDate.HasValue)
{
    // What is the runtime type of q? And what is its compiletime type?
    q = q.Where(item => item.Date > startDate.Value);
}

ゼロ以外のコストは、メンテナンスと文書化のコスト (実装を公開すると変更が難しくなり、文書化する必要があります)、およびユーザーにとっての複雑さの増加で構成されます。

于 2013-11-06T09:07:41.447 に答える