15

クラスを想像してみましょIList<T>IQueryable<T>

そのクラスにはint TotalItemsプロパティがあり、(それほど驚くべきことではありませんが) クエリ可能または列挙可能なパラメーターの数を取得/設定します。

IEnumerable<T>パラメータとして使用すると、

//simplified
public Pagination(IEnumerable<T> query)
    {
        TotalItems = query.Count();
    }

Count()メソッドは (私が間違っていなければ、それがポイントです)になりEnumerable.Count()ます。したがって、クエリがIQueryable<T>(から継承するIEnumerable<T>) であっても、列挙されます (これは明らかに「db クエリ」では望ましくありません)。

Queryable.Count()myIEnumerable<T>が実際に である場合にメソッドを使用する方法はありますIQueryable<T>か、またはこの場合、たとえば 2 ctor を使用して設計を変更する必要がありますか?

//simplified
public Pagination(IEnumerable<T> query)
    {
         TotalItems = query.Count();
    }
public Pagination(IQueryable<T> query)
    {
         TotalItems = query.Count();
    }

EDITIQueryable<T>から継承することは、同じ名前の拡張メソッドがあるという事実とIEnumerable<T>は何の関係もないこと、そして「同じように見える」拡張メソッドに同じ名前を付けるのはいいことだと理解していますが、それでも私はそれだと思い ます時々混乱する...IEnumerable<T>IQueryable<T>

好奇心のための一般的な質問

それらは、同じ「アーキテクチャ」を持つフレームワークの他の例ですか:継承+拡張メソッドの共通名?

4

2 に答える 2

8

質問で示したように、2 つのコンストラクターのオーバーロードが必要です。IQueryableこれにより、メソッドを使用するか、メソッドを使用するかは呼び出し元IEnumerableに任されます。

誰かがするなら:

Pagination pager = new Pagination(query.AsEnumerable());

次に、オブジェクトをIEnumearbleではなくとして処理することを明らかに望んでいますIQueryable。おそらく彼らはそれを知っていて、クエリプロバイダーによって実装されSkipTakeいないため、ページネーションは失敗し、Linq-to-objects として評価する必要があります。

2 つのオーバーロードを使用することで、自分で理解しようとするのではなく、クラスのユーザーがインメモリ シーケンスとクエリのどちらを処理しているかを十分な情報に基づいて決定できます。

于 2013-03-08T16:33:39.893 に答える
1

まあ、あなたはすることができます:

TotalItems = enumerable.AsQueryable().Count();

これは、ネイティブのクエリ可能オブジェクトに対してクエリプロバイダーのCount実装を直接使用するか、それ以外の場合はLINQ to Objectsにフォールバックします(使用するためのオーバーヘッドがありますEnumerableQuery)。

別の解決策(潜在的により効率的):

var queryable = enumerable as IQueryable<T>;
TotalItems = queryable != null ? queryable.Count() : enumerable.Count();

ただし、クエリ可能な実装ICollectionまたはICollection<T>効率的な場合(一部のクエリプロバイダーの場合のように)、LINQ内の最適化により、既存のソリューションでもうまく機能する可能性があることに注意してください(可能な場合Countはこれらのインターフェイスのプロパティを使用します)。あなたIList<T>の場合、それはを実装しているので、常にこの最適化を使用しますICollection<T>

于 2013-03-08T15:37:46.943 に答える