web-dev-qa-db-ja.com

拡張メソッドと継承

どのような場合にどちらを使用するかを決定するのに役立つ経験則はありますか?ほとんどの場合、どちらか一方を優先する必要がありますか?

ありがとう!

42
djcouchycouch

拡張メソッドは便利ですが、元のクラスにアタッチされておらず、コードがどこにあるかについての手がかりがないため、通常のメソッドよりもIDE)で見つけるのは困難です。 。いくつかの ベストプラクティスの提案 それらを配置する場所とそれらに名前を付ける方法についてありますが、これらは単なるガイドラインであり、誰かがそれらに従うという保証はありません。

通常、コードにアクセスできない、よく知られた、よく使用されるクラスまたは.Net基本クラスなどのインターフェイスにのみ機能を追加する場合は、拡張メソッドを使用します。拡張メソッドには、元のアセンブリが必要なだけでなく、拡張メソッドを含むアセンブリが必要であるという制約もあります。これは、コードのコンシューマーが理解する必要があります。

継承を使用すると、機能を追加、削除、またはオーバーライドし、クラスをビルドするときに常にクラスに存在するようにすることができます。

33
womp

拡張メソッドは、同じ動作を共有する必要があるが、それ以外の場合は異なるさまざまなタイプに実装を提供する場合に使用する必要があります。これが、インターフェイスで拡張メソッドが頻繁に使用されている理由です。これは、インターフェイスの特定の実装が特定の動作の同じ実装を持つことを保証する非常に強力なツールだからです。

たとえば、SkipおよびTake拡張メソッド。

14
Joseph

ええと...あなたはいつもse継承をすることはできません。たとえば、Stringは封印されたクラスです。拡張メソッドが本当に優れているのはそのような場合です。

一般に、拡張メソッドは、静的クラスに入れる可能性があるが、特定のタイプのインスタンスに対して動作する小さなユーティリティに最適です。文字列は良い例です。ほとんどの人が、文字列に対して小さな操作を行うための独自の小さな文字列拡張メソッドを持っています。

拡張メソッドのもう1つの優れた場所は、列挙に反対することです。ほとんどの場合、作成する[Flags]列挙に対してHasFlag拡張メソッドを含めます。

8
Randolpho

可能な限り、継承を使用してください拡張メソッドの代わりに

編集

私はこれを短くシンプルに保つことを好みますが、もちろんフォローアップの質問に答えます。

継承が可能な場合、つまり、シールされていないクラスの場合、ほとんどの場合、拡張メソッドよりも優れたオプションです。実際、これは、wompが参照している ベストプラクティスドキュメント が言っていることです。 「拡張メソッドに注意する」、「所有していない型を拡張する前によく考えてください」、「クラス拡張よりもインターフェイス拡張を優先する」などの見出しがあります。言い換えれば、それは私のワンライナーが何をしたかをより詳細に述べているだけです。

この記事には詳細な理由が記載されていますが、肝心なのは、これが拡張メソッドが使用されるように設計された方法であるということです。これらはゲームの後半に少しの構文糖衣として言語に追加され、MSが戻って車輪の再発明をしなくてもLINQにくさびを入れることができるようになりました。これは、それらが何に役立つかについての標準的な例です。もう1つの良い例は、次のようなユーティリティメソッドを追加することです。

public static string FormatWith(this string format, params object[] args)
{ return string.Format(CultureInfo.InvariantCulture, format, args); }

この場合、文字列は封印されているため、拡張メソッドがこの追加機能を実現する唯一の方法であることに注意してください。

相続をめぐる構成については、これは真実ですが、ここでは関連性がわかりません。拡張メソッドを使用している場合でも継承を使用している場合でも、目的はインターフェイスを変更して別のメソッドを許可することです。このメソッドの実装方法は、構成、ジェネリック、またはその他の手法のいずれであっても、直交しています。

8
Steven Sudit

それらは非常に異なります。たとえば、LINQ標準クエリ演算子は、継承では実装が難しい拡張メソッドの優れた例ですが、クラスにアクセスでき、ソースを変更できる場合は、継承を使用することをお勧めします。
[〜#〜]編集[〜#〜]
そしてここに私が見つけたいくつかのルールがあります C#3.0の機能:拡張メソッド

  • 拡張メソッドを使用して既存のメソッドをオーバーライドすることはできません
  • インスタンスメソッドと同じ名前とシグネチャを持つ拡張メソッドは呼び出されません
  • 拡張メソッドの概念は、フィールド、プロパティ、またはイベントには適用できません。
  • 拡張メソッドは慎重に使用してください。使いすぎは悪いことです。
2
Arsen Mkrtchyan

拡張メソッドが主に設計されている場合を除いて、継承に固執します-封印されたクラスを拡張するか、スコープ固有の拡張を作成します。また、これらは静的であるため、これらが他のクラスでオーバーライドする必要のあるメソッドと動作である場合、拡張機能を実際に使用することはできません。

拡張メソッドには、その実装に固有の利点である1つの非常に優れた機能があります。これらは静的メソッドであるため、nullオブジェクトで呼び出すことができます。

例えば:

string a = null;
return a.IfNullOrEmpty("Default Value");

このような実装は素晴らしいですが、技術的には単なる構文糖衣です。私見ですが、コードをよりクリーンで読みやすくするものは何でも素晴らしいです。

私はそれが好きではありませんが、それらは実際には発見できません。そのコードをあるクラスから別のクラスにコピーすると、それが定義されている名前空間を検索する必要があります。

2
Brian Rudolph

それは本当にあなたが解決する必要のある問題に依存します、ほとんどの状況でクラス継承とインターフェースは拡張メソッドより自然に理にかなっているので、好まれるべきです。

一方、Extensionsを使用すると、1つだけではなくクラスを適用する便利なメソッドを作成できます。そうしないと、継承を使用するのがはるかに面倒になります。達成することはほとんど不可能ではありません。

大事なことを言い忘れましたが、Extensionsを使用すると、.NET Frameworkの組み込みクラスサードパーティクラスを拡張できます。ソースコードを所有していないか、ソースコードにアクセスできません。

正当な理由で拡張メソッドが使用されるいくつかの例を次に示します。


LinqPad 拡張メソッドを使用します。たとえば、あらゆる種類のオブジェクトのコンテンツを出力ウィンドウにダンプ(印刷)できる.Dump()メソッドです。


.NET Framework自体は、多くの場所で拡張メソッドを使用します。たとえば、 Linq :

public static TSource FirstOrDefault<TSource>(this 
                        System.Collections.Generic.IEnumerable<TSource> source)

これは、最初の要素またはデフォルトのany列挙可能なコレクションof anyオブジェクトタイプを返します。


拡張メソッドが継承よりも優れている例は次のとおりです。既存のオブジェクトのcreate clone (copy)が可能なメソッドを作成するとします。拡張機能(およびジェネリックスとリフレクション)を使用すると、それを行うことができます この方法

1
Matt

拡張メソッドはうまく機能しませんOO設計。コードベースにアクセスできない封印されたクラスで使用する必要があると言うのはばかげています。封印されていてアクセスできないクラスは、おそらく理由(パフォーマンス、スレッドセーフ)で封印されており、これらのクラスに盲目的に機能をタグ付けすることは、まさに危険です。純粋なOOの方法で、デコレータパターンを実装する方法は常にあります。そうしないと、コードの読み取り、保守、リファクタリングが難しくなります。原則として、言語の機能の臭いが悪い場合は、避ける必要があります。拡張メソッドが役立つ例を1つ見つけることができると確信しています。ただし、真実は、最小限のOOトレーニングでこれらの開発者によって機能が悪用されることです。

0
ComeIn