AsQueryable()
の目的は、IEnumerable
をIQueryable
を期待する可能性のあるメソッドに渡すことができるようにするためですか、それともIEnumerable
をIQueryable
として表す有用な理由がありますか?たとえば、次のような場合に想定されていますか?
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
を使用する実際の使用例は何ですか?
主な用途がいくつかあります。
他の回答で述べたように、メモリ内のデータソースを使用してクエリ可能なデータソースをモックすることで、列挙不可能なベースIQueryable
で最終的に使用されるメソッドをより簡単にテストできます。
インメモリシーケンスまたは外部データソースに適用できるコレクションを操作するためのヘルパーメソッドを作成できます。ヘルプメソッドを記述してIQueryable
を完全に使用する場合は、すべての列挙型でAsQueryable
を使用してそれらを使用できます。これにより、非常に一般化されたヘルパーメソッドの2つの別個のバージョンを記述することを回避できます。
これにより、クエリ可能オブジェクトのコンパイル時タイプを、より派生したタイプではなく、IQueryable
に変更できます。実質的にIQueryable
でAsEnumerable
を使用するのと同時に、IEnumerable
で使用します。 IQueryable
を実装するオブジェクトがありますが、インスタンスSelect
メソッドもあります。その場合、LINQ Select
メソッドを使用する場合は、オブジェクトのコンパイル時の型をIQueryable
に変更する必要があります。キャストすることもできますが、AsQueryable
メソッドを使用すると、型推論を利用できます。これは、ジェネリック引数リストが複雑な場合は単純に便利です。実際には、ジェネリック引数のいずれかが匿名型の場合はnecessaryです。
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()メソッドでできることは、モックを設定するときにコンパイラを満足させることだけです。
ただし、これがアプリケーションコードで使用される場所に興味があります。
Sanjuroが指摘したように、AsQueryable()の目的は Linq To ObjectsおよびLinq To SQLでのAsQueryableの使用 で説明されています。特に、記事には、
これは、エンティティの特定のメソッドがTのIQueryableを返し、一部のメソッドがListを返すという実際のWordシナリオで優れた利点を提供します。ただし、コレクションがTのIQueryableまたはTのIEnumerableとして返されるかどうかに関係なく、すべてのコレクションに適用する必要があるビジネスルールフィルターがあります。パフォーマンスの観点から、データベースでビジネスフィルターの実行を活用したい場合それ以外の場合、コレクションはIQueryableを実装し、Linqを使用してデリゲートのオブジェクト実装にメモリ内のビジネスフィルターを適用します。
AsQueryable()の目的については、この記事で詳しく説明しています Linq To ObjectsおよびLinq To SQL でAsQueryableを使用する
MSDN Queryable.AsQueryableメソッドの備考セクションから:
ソースのタイプがIQueryableを実装している場合、AsQueryable(IEnumerable)はそれを直接返します。それ以外の場合は、QueryableのメソッドではなくEnumerableの同等のクエリ演算子メソッドを呼び出してクエリを実行するIQueryableを返します。
それはまさに上記の記事で言及され使用されているものです。あなたの例では、orderRepo.GetAllが返すもの、IEnumerableまたはIQueryable(Linq to Sql)に依存します。 IQueryableを返す場合、Count()メソッドはデータベースで実行されます。それ以外の場合は、メモリで実行されます。参照記事の例を注意深く見てください。
インターフェイスIQueryable
引用ドキュメント:
IQueryableインターフェイスは、クエリプロバイダーによる実装を目的としています。
そのため、.NETでdatastractureをクエリ可能にするつもりの場合、そのデータ構造不要なものを列挙したり、有効な列挙子を持つことができます。
IEnumerator
は反復処理のためのインターフェースですデータのストリーム代わりに。