IOrderedEnumerable
純粋にセマンティック値の戻り値の型として使用する必要がありますか?
たとえば、プレゼンテーション レイヤーでモデルを使用する場合、コレクションに順序付けが必要か、または既に順序付けられているかをどのように知ることができますか?
ORDER BY
リポジトリがストアド プロシージャを句でラップする場合はどうでしょうか。リポジトリは を返す必要がありますIOrderedEnumerable
か? そして、それはどのように達成されますか?
IOrderedEnumerable
純粋にセマンティック値の戻り値の型として使用する必要がありますか?
たとえば、プレゼンテーション レイヤーでモデルを使用する場合、コレクションに順序付けが必要か、または既に順序付けられているかをどのように知ることができますか?
ORDER BY
リポジトリがストアド プロシージャを句でラップする場合はどうでしょうか。リポジトリは を返す必要がありますIOrderedEnumerable
か? そして、それはどのように達成されますか?
私はそれが良い考えだとは思わない:
IOrderedEnumerable は、純粋にセマンティック値の戻り値の型として使用する必要がありますか?
たとえば、プレゼンテーション レイヤーでモデルを使用する場合、コレクションに順序付けが必要か、または既に順序付けられているかをどのように知ることができますか?
どのキーで順序付けられているかがわからない場合、シーケンスが順序付けられていることを知ることに何の意味がありますか? インターフェイスのポイントはIOrderedEnumerable
、2 番目の並べ替え基準を追加できるようにすることです。これは、1 番目の基準が何であるかがわからない場合、あまり意味がありません。
リポジトリがストアド プロシージャを ORDER BY 句でラップする場合はどうでしょうか。リポジトリは IOrderedEnumerable を返す必要がありますか? そして、それはどのように達成されますか?
これは意味がありません。既に述べたように、IOrderedEnumerable
は 2 番目の並べ替え条件を追加するために使用されますが、データがストアド プロシージャによって返された時点では、データは既に並べ替えられており、2 番目の並べ替え基準を追加するには遅すぎます。できることは完全に再ソートすることだけなのでThenBy
、結果を呼び出しても期待した効果は得られません。
トーマスが指摘しているように、オブジェクトが であるということは、IOrderedEnumerable
それが何らかの方法で順序付けられているということだけを教えてくれます。
また、戻り値の型はオーバーライドとコンパイル可能性に影響しますが、ランタイム チェックには影響しないことに注意してください。
private static IOrderedEnumerable<int> ReturnOrdered(){return new int[]{1,2,3}.OrderBy(x => x);}
private static IEnumerable<int> ReturnOrderUnknown(){return ReturnOrdered();}//same object, diff return type.
private static void UseEnumerable(IEnumerable<int> col){Console.WriteLine("Unordered");}
private static void UseEnumerable(IOrderedEnumerable<int> col){Console.WriteLine("Ordered");}
private static void ExamineEnumerable(IEnumerable<int> col)
{
if(col is IOrderedEnumerable<int>)
Console.WriteLine("Enumerable is ordered");
else
Console.WriteLine("Enumerable is unordered");
}
public static void Main(string[] args)
{
//Demonstrate compile-time loses info from return types
//if variable can take either:
var orderUnknown = ReturnOrderUnknown();
UseEnumerable(orderUnknown);//"Unordered";
orderUnknown = ReturnOrdered();
UseEnumerable(orderUnknown);//"Unordered"
//Demonstate this wasn't a bug in the overload selection:
UseEnumerable(ReturnOrdered());//"Ordered"'
//Demonstrate run-time will see "deeper" than the return type anyway:
ExamineEnumerable(ReturnOrderUnknown());//Enumerable is ordered.
}
IEnumerable<T>
このため、状況によってどちらかが返されるか、呼び出し元に返される場合がある場合IOrderedEnumerable<T>
、変数は as 型にIEnumerable<T>
なり、戻り値の型からの情報は失われます。一方、戻り値の型が何であっても、呼び出し元は型が本当に であるかどうかを判断できますIOrderedEnumerable<T>
。
いずれにせよ、戻り値の型はそれほど重要ではありませんでした。
戻り値の型のトレードオフは、呼び出し元にとっての有用性と呼び出し先にとっての柔軟性との間です。
現在 で終わるメソッドを考えてみましょうreturn currentResults.ToList()
。次の戻り値の型が可能です。
List<T>
IList<T>
ICollection<T>
IEnumerable<T>
IList
ICollection
IEnumerable
object
オブジェクトと非ジェネリック型は、有用である可能性が低いため、今すぐ除外しましょう (それらが有用な場合、それらを使用するのはおそらく簡単な決定です)。これは次のとおりです。
List<T>
IList<T>
ICollection<T>
IEnumerable<T>
リストの上位に行くほど、その型によって公開され、下の型では公開されない機能を呼び出し元が利用できるようになります。リストの下に行くほど、呼び出し先が将来実装を変更できる柔軟性が高くなります。したがって、理想的には、メソッドの目的 (呼び出し元に有用な機能を公開し、既に提供している機能を提供するために新しいコレクションが作成されるケースを減らすため) のコンテキストで意味のあるリストの上位に行きたいと考えていますが、それ以上にはなりません。 (将来の変更を可能にするため)。
したがって、 anまたは an (orまたは)IOrderedEnumerable<TElement>
として返すことができるan がある場合に戻ります。IOrderedEnumerable<TElement>
IEnumerable<T>
IEnumerable
object
問題は、これがIOrderedEnumerable
本質的にメソッドの目的に関連しているという事実なのか、それとも単に実装のアーティファクトなのかということです。
ReturnProducts
同じ製品が異なる価格で 2 回提供されたケースを除去する実装の一部として、たまたま価格で注文するメソッドがあった場合IEnumerable<Product>
、呼び出し元はそれが注文されたことを気にするべきではなく、確かにそうすべきであるため、を返す必要があります。それに依存する必要はありません。
ReturnProductsOrderedByPrice
順序付けが目的の一部であるメソッドがあった場合、を返す必要IOrderedEnumerable<Product>
があります。これは、その目的により密接に関連しているためです。その後の実装の変更によって壊れました。CreateOrderedEnumerable
ThenBy
ThenByDescending
編集:これの2番目の部分を見逃しました。
リポジトリがストアド プロシージャを ORDER BY 句でラップする場合はどうでしょうか。リポジトリは IOrderedEnumerable を返す必要がありますか? そして、それはどのように達成されますか?
可能であれば(またはおそらく)、それは非常に良い考えIOrderedQueryable<T>
です。しかし、それは単純ではありません。
まず、 の後に続くものは何もORDER BY
順序付けを元に戻すことができないことを確認する必要があります。これは簡単ではないかもしれません。
次に、 への呼び出しでこの順序を元に戻してはなりませんCreateOrderedEnumerable<TKey>()
。
たとえば、フィールドA
、B
、C
およびを持つ要素がD
、使用されたものから返された場合、 を実装するORDER BY A DESCENDING, B
と呼ばれる型が返されます。次に、とが注文されたフィールドであるという事実を保存する必要があります。への呼び出し(これは whatおよびcall into でもあります)は、データベースによって返されたのと同じ規則 (データベースと .NET の間の照合は困難な場合があります) によって、 とについて同等に比較される要素のグループを取る必要があります。これらのグループ内では、 に従って順序付けする必要があります。MyOrderedEnumerable<El>
IOrderedEnumerable<El>
A
B
CreateOrderedEnumerable(e => e.D, Comparer<int>.Default, false)
ThenBy
ThenByDescending
A
B
cmp.Compare(e0.D, e1.D)
それができれば、非常に便利であり、すべての呼び出しで使用されるすべてのクエリにIOrderedEnumerable
if句が存在する場合、戻り値の型が適切です。ORDER BY
そうでなければ、IOrderedEnumerable
それが提供する契約を履行できなかったため、嘘になり、役に立たないわけではありません.