4

.NET 3.5 を検討し始めたばかりなので、この種の質問が以前に行われたことがある場合はご容赦ください。suteki shop から MVC e コマース製品をダウンロードしたばかりなので、拡張メソッドの適切な使用法に苦労しています。このプロジェクトには、IRepository を拡張する非常に標準的なリポジトリ パターンがあります。

このインターフェースによって公開される基本機能を拡張するために、拡張メソッドが使用されます。

public static class CategoryRepositoryExtensions
{
    public static Category GetRootCategory(this IRepository<Category> categoryRepository)
    {
     return categoryRepository.GetById(1);
    }
}

これで問題ありませんが、インターフェイスは、私が考える限り、それらを実装するオブジェクトへのコントラクトとして機能します。

リポジトリがインターフェース化されているという事実は、データ層にとらわれないアプローチの試みを示唆しています。とはいえ、独自のデータ レイヤーを作成する場合、リポジトリ クラスを実装するクラスに対する契約上の要件を確実に満たすために、どの拡張メソッドを作成する必要があるかについて混乱するでしょう。

IRepository を作成してから拡張する古い方法では、必要なものの可視性が大幅に向上するようです。

ICategoryRepoitory : IRepository<Category>
{
     Category GetRootCategory();
}

だから私の質問は、この拡張メソッドの使用は他の人にとって間違っているように見えるのでしょうか? そうでない場合、なぜですか?私はこれについてうめき声を上げるべきではありませんか?

編集:

上記の例は、拡張メソッドが非常に役立つ理由の良い例のようです。

私の問題は、データ アクセス メカニズム アセンブリの拡張メソッドでデータ アクセス固有の実装が動かなくなった場合だと思います。

そうすれば、別のメカニズムに交換する場合、そのアセンブリで同様の拡張メソッドを作成する必要があります。

4

4 に答える 4

5

重要なのは、すべてをIRepository<T>適切に実装した場合、(データレイヤーの実装者として)ルートカテゴリについてまったく知る必要がないということです。この拡張メソッドの範囲では、カテゴリのリポジトリにはID 1のルートカテゴリがあると想定されています。これは完全に合理的な前提であり、有用な前提です。派生クラスを作成する必要はありません(これは実用的でない可能性があります-データレイヤーには、実装から派生するのが難しいファクトリなどがある場合があります)。

現在、拡張メソッドは、そのスコープが適切である場合にのみ適用できます。つまり、ルートカテゴリに関する仮定が有効になる名前空間(または密接に関連する名前空間)にある場合です。

「古い」方法は、実際にはインターフェースを拡張するものではないと思います。IRepository<Category>これは、を使用する通常の静的メソッドIRepository<Category>です。ここで、拡張メソッドによって生活がより快適になります。代わりに実際に継承を使用した場合は、今も使用するのが適切かもしれません。残念ながら、システムのアーキテクチャについては、確かにそれを言うには十分な知識がありません。

于 2008-11-12T21:01:52.297 に答える
4

拡張メソッドの概念は、一部の著者が呼ぶように、単なる構文糖衣です。コードは読みやすくなりますが、理解しにくくなります。最終的に、拡張メソッドは、手続き型パラダイムの遺産である静的メソッドにすぎません。コードが密結合になり、まとまりがなくなり、テストや再利用が難しくなります。

私は、C# プログラミング言語のこの傾向に偏見を持っています。この機能は魅力的ですが、何のメリットもありません。逆に、コードの複雑さが増します。

于 2009-10-09T07:13:43.790 に答える
1

それは同じことではありません。拡張メソッドは構文上の利便性であり、それ以上のものではなく、確かに契約上の要件ではありません。自分のクラスでそれらを「実装」することはありません。上記の例の場合:

using CategoryRepositoryExtensions;
...
Category c = r.GetRootCategory();

まったく同じです:

Category c = CategoryRepositoryExtensions.GetRootCategory(r);

したがって、インターフェースの実装者に追加の要件はありません。

于 2008-11-12T21:03:02.667 に答える
0

はい、あなたが言及した例では、それは直感に反しているように見えます。その理由は、単一のレベルで単一のオブジェクトを操作しているためです。IQueryable / IEnumerableコレクションを使用している場合は、拡張メソッドが最も役立つことがわかりました。

たとえば。2つのシナリオを考えてみましょう。

  • シナリオ1:製品xを含むすべての注文のリストを取得する

  • シナリオ2:製品xを含み、郵便番号yに出荷されたすべての注文のリストを取得します

従来の/インターフェース主導のアプローチを使用していた場合、2つを定義すると、2つの異なるインターフェースを定義したくなるかもしれません。拡張メソッドを使用する場合は、次のようなものを使用できます

シナリオ1

<IEnumerable> orders1Enumerable = OrderRepository.GetAllOrders()
                                     .ContainingProductCode(x);

シナリオ2

<IEnumerable> orders2Enumerable = OrderRepository.GetAllOrders()
                                     .ContainingProductCode(x)
                                     .WithShippingZipCode(y);

これを行うと、フレームワークはこれらの拡張メソッドをチェーンすることにより、適切なSQLをオンザフライで作成します

お役に立てれば

于 2008-11-12T21:31:22.500 に答える