AsQueryable()の目的は何ですか?


107

の目的は、期待する可能性のあるメソッドにをAsQueryable()渡すことができるようにすることですか、それとも次のように表すのに役立つ理由がありますか?たとえば、次のような場合が想定されています。IEnumerableIQueryableIEnumerableIQueryable

IEnumerable<Order> orders = orderRepo.GetAll();

// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());

public static int CountOrders(IQueryable<Order> ordersQuery)
{
    return ordersQuery.Count();
}

それとも実際に何か違うことをするのですか?

IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();

IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);

// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();

実行しIQueryable、その実行後に同じことをやって終了することをこれらの拡張メソッドのバージョンはちょうど式を構築しますか?私の主な質問は、使用の実際のユースケースはAsQueryable何ですか?

回答:


65

主な用途はいくつかあります。

  1. 他の回答で述べたように、これを使用して、メモリ内データソースを使用してクエリ可能なデータソースをモックすることができるため、最終的に非列挙型ベースで使用されるメソッドをより簡単にテストできますIQueryable

  2. インメモリシーケンスまたは外部データソースに適用できるコレクションを操作するヘルパーメソッドを記述できます。ヘルプメソッドをIQueryable完全に使用するように記述した場合はAsQueryable、すべての列挙型でそれらを使用できます。これにより、非常に一般化されたヘルパーメソッドの2つの個別のバージョンを記述することを回避できます。

  3. これにより、クエリ可能オブジェクトのコンパイル時の型を、IQueryableより派生した型ではなく、に変更できます。事実上; で使用するとIQueryable同時にで使用AsEnumerableしますIEnumerable。実装するオブジェクトがあるかもしれませんが、IQueryableインスタンスSelectメソッドも持っています。その場合、LINQ Selectメソッドを使用したい場合は、オブジェクトのコンパイル時のタイプをに変更する必要がありますIQueryable。そのままキャストすることもできAsQueryableますが、メソッドを使用することで、型推論を利用できます。これは、ジェネリック引数リストが複雑な場合に便利であり、ジェネリック引数のいずれかが匿名型である場合に実際に必要です。


リバイバルをありがとう。これが最も完全であるため、これを回答としてマークします。
Ocelot20、2013

5
それがIQueryable<T>派生してIEnumerable<T>いるとしたら、「列挙できないベースのIQueryable」が何を意味するのか説明していただけますか?
2016

2
@Dai IQueryableは、単にラップされただけではなく、IEnumerable実際にの追加機能を利用するを指しIQueryableます。
サービー

#1はまさに私が求めていたものです。確認していただきありがとうございます。
one.beat.consumer

12

AsQueryableで最も有効なケースは単体テストです。次のやや工夫された例があるとしましょう

public interface IWidgetRepository
{
   IQueryable<Widget> Retrieve();
} 

public class WidgetController
{
   public IWidgetRepository WidgetRepository {get; set;}


   public IQueryable<Widget> Get()
   {
      return WidgetRepository.Retrieve();
   }
}

コントローラーからリポジトリーから返された結果を確実に戻すための単体テストを作成したいと思います。次のようになります。

[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{    
    var widget1 = new Widget();
    var widget2 = new Widget();
    var listOfWidgets = new List<Widget>() {widget1, widget2};
    var widgetRepository = new Mock<IWidgetRepository>();
    widgetRepository.Setup(r => r.Retrieve())
      .Returns(listOfWidgets.AsQueryable());
    var controller = new WidgetController();
    controller.WidgetRepository = widgetRepository.Object;

    var results = controller.Get();

    Assert.AreEqual(2, results.Count());
    Assert.IsTrue(results.Contains(widget1));
    Assert.IsTrue(results.Contains(widget2));
}

実際、AsQueryable()メソッドを使用すると、モックを設定するときにコンパイラーを満足させることができます。

これがアプリケーションコードのどこで使用されているかに興味があります。


11

sanjuroが述べたように、AsQueryable()の目的は、Linq ToオブジェクトおよびLinq To SQLでのAsQueryableの使用で説明されています。特に、この記事では、

これは、TのIQueryableを返すエンティティに特定のメソッドがあり、一部のメソッドがListを返す実際のシナリオで優れた利点を提供します。ただし、コレクションがTのIQueryableまたはTのIEnumerableとして返されるかどうかに関係なく、すべてのコレクションに適用する必要があるビジネスルールフィルターがあります。パフォーマンスの観点から、データベースでのビジネスフィルターの実行を活用したい場合コレクションはIQueryableを実装します。それ以外の場合はフォールバックして、デリゲートのオブジェクト実装にLinqを使用してメモリ内のビジネスフィルターを適用します。


6

AsQueryable()の目的は、この記事で大きく説明されています。LinqToオブジェクトおよびLinq To SQLでのAsQueryableの使用

MSDN Queryable.AsQueryableメソッドの備考セクションから:

ソースのタイプがIQueryableを実装している場合、AsQueryable(IEnumerable)はそれを直接返します。それ以外の場合は、QueryableではなくEnumerableで同等のクエリ演算子メソッドを呼び出してクエリを実行するIQueryableを返します。

それはまさに上記の記事で言及され使用されているものです。あなたの例では、それは、orderRepo.GetAllが返すもの、IEnumerableまたはIQueryable(Linq to Sql)に依存します。IQueryableを返す場合、Count()メソッドはデータベースで実行されます。それ以外の場合は、メモリ内で実行されます。参照記事の例を注意深く見てください。


3

インターフェイスIQueryable引用ドキュメント:

IQueryableインターフェイスは、クエリプロバイダーによる実装を目的としています。

そのため、データ構造を.NETでクエリ可能にするつもりの場合、必要のないデータ構造を列挙するか、有効な列挙子を使用できます。

IEnumerator代わりに、データのストリームを反復して処理するためのインターフェースです。


「このデータ構造は、列挙することも、有効な列挙子を持つこともできます」と言い換えていただけませんか。私は違いを理解IQueryableしてIEnumerable、私はのためのユースケースを理解していないAsQueryable拡張メソッドを。私はその文で少しつまずきましたが、私は(賛成票に基づいて)探している答えがあるのではないかと思います。
Ocelot20 2013年

@ Ocelot20:つまり、IQueryableを実装するプロバイダーによって提示される帽子データ構造は、列挙機能を提供しない可能性があります。プロバイダー次第です。引用ドキュメント:「列挙可能な結果を​​返さないクエリは、Executeメソッドが呼び出されると実行されます。」
Tigran 2013年

多分私は明白な何かを見逃しているかもしれませんが、それでも「なぜ私は使用する必要があるのAsQueryable()でしょうか?」という答えが表示されません。IEnumerable(既に列挙機能を提供できるもの)から始めている場合IQueryable、拡張メソッドを使用するように変換する必要があるのはなぜAsQueryable()ですか?多分これが便利になる場所を説明する小さなコード例でしょうか?あなたの説明に何か欠けているようです。御時間ありがとうございます。
Ocelot20 2013年

@ Ocelot20:クエリプロバイダーを記述するために必要な違いを実際に示すため。あなたは私たちが持っていることを知ってlinq to sqllinq to xmlあなたが書き込みしたい場合など.. linqターゲットドライバあなたのデータstrucutresを(linq to your dataあなたのAPIのユーザーが実行する可能性がありますので、)linqに対してクエリをあなたのデータ構造を、あなたが選択する必要がIQueryable
Tigran

2
IQueryableとの違いを説明しているようですIEnumerable。私は違いを知っています、そしてそれは私が求めているものではありません。誰かがを実装するものを取りIEnumerable、それを拡張メソッドIQueryableを使用してに変換する理由を尋ねていAsQueryableます。それはあなたが答えていることですか?私はまだわかりません...
Ocelot20
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.