.NET の拡張メソッドとは何ですか?
編集:拡張メソッドの使用にフォローアップの質問を投稿しました
拡張メソッドを使用すると、開発者は既存の CLR 型のパブリック コントラクトに新しいメソッドを追加できます。サブクラス化や元の型の再コンパイルは必要ありません。
拡張メソッドは、今日の動的言語で一般的な「ダック タイピング」サポートの柔軟性と、厳密に型指定された言語のパフォーマンスおよびコンパイル時の検証を融合するのに役立ちます。
参照: http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx
次に、拡張メソッドのサンプルを示します (this
最初のパラメーターの前にあるキーワードに注意してください)。
public static bool IsValidEmailAddress(this string s)
{
Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
return regex.IsMatch(s);
}
上記のメソッドは、次のように、任意の文字列から直接呼び出すことができます。
bool isValid = "so@mmas.com".IsValidEmailAddress();
追加されたメソッドは、IntelliSense にも表示されます。
(ソース: scottgu.com )
拡張メソッドの実際の使用に関しては、新しいクラスを派生させずに新しいメソッドをクラスに追加することがあります。
次の例を見てください。
public class Extended {
public int Sum() {
return 7+3+2;
}
}
public static class Extending {
public static float Average(this Extended extnd) {
return extnd.Sum() / 3;
}
}
ご覧のとおり、クラスExtending
は average という名前のメソッドを class に追加していExtended
ます。平均を取得するには、クラスaverage
に属しているため、メソッドを呼び出します。extended
Extended ex = new Extended();
Console.WriteLine(ex.average());
元のソース コードにアクセスできなくても、何かにメソッドを追加できます。その点を説明する例を考えてみましょう。
私が犬を飼っているとします。すべての犬 - 犬タイプのすべての動物 - は、特定のことを行います。
犬ができることはすべて「メソッド」と呼ばれます。ここで、オブジェクト指向天国の偉大なプログラマーが犬のクラスにメソッドを追加するのを忘れたとしましょう: FetchNewspaper()。あなたは言うことができるようにしたい:
rex.FetchNewspaper(); // or
beethoven.FetchNewspaper();
……ソースコードにアクセスできなくても。
あなたの犬にそれをさせるためにどのようにしていますか?唯一の解決策は、「拡張メソッド」を作成することです。
(以下の最初のパラメーターの前にある「this」キーワードに注意してください):
public static void FetchNewsPaper(this Dog familyDog)
{
Console.Writeline(“Goes to get newspaper!”)
}
犬に新聞を届けさせたい場合は、次のようにします。
Dog freddie_the_family_dog = new Dog();
freddie_the_family_dog.FetchNewspaper();
ソース コードがなくてもクラスにメソッドを追加できます。これは非常に便利です。
拡張メソッドは、ソースコードがない場合でも、別のクラスへのメソッドの追加をシミュレートできる「コンパイラトリック」です。
例えば:
using System.Collections;
public static class TypeExtensions
{
/// <summary>
/// Gets a value that indicates whether or not the collection is empty.
/// </summary>
public static bool IsEmpty(this CollectionBase item)
{
return item.Count == 0;
}
}
理論的には、すべてのコレクションクラスに、IsEmpty
メソッドにアイテムがない場合にtrueを返すメソッドが含まれるようになりました(上記のクラスを定義する名前空間が含まれている場合)。
重要なことを見逃してしまったら、誰かが指摘してくれると思います。(お願いします!)
当然、拡張メソッドの宣言にはルールがあります(静的である必要があり、最初のパラメーターの前にthis
キーワードが続く必要があります)。
拡張メソッドは、拡張しているように見えるクラスを実際には変更しません。代わりに、コンパイラは関数呼び出しをマングルして、実行時にメソッドを適切に呼び出します。ただし、拡張メソッドは、独特のアイコンが付いたインテリセンスドロップダウンに適切に表示され、通常のメソッドと同じように文書化できます(上記を参照)。
注:同じシグニチャーを持つメソッドがすでに存在する場合、拡張メソッドがメソッドを置き換えることはありません。
拡張メソッドは、開発者が制御できないオブジェクトにメソッドを「追加」する方法です。
たとえば、"DoSomething()" メソッドを System.Windows.Forms オブジェクトに追加する場合、そのコードにアクセスできないため、次の構文でフォームの拡張メソッドを作成するだけです。
Public Module MyExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Sub DoSomething(ByVal source As System.Windows.Forms.Form)
'Do Something
End Sub
End Module
これで、フォーム内で「Me.DoSomething()」を呼び出すことができます。
要約すると、継承なしで既存のオブジェクトに機能を追加する方法です。
VB.Net の例を次に示します。Extension() 属性に注意してください。これをプロジェクトのモジュールに配置します。
Imports System.Runtime.CompilerServices
<Extension()> _
Public Function IsValidEmailAddress(ByVal s As String) As Boolean
If String.IsNullOrEmpty(s) Then Return False
Return Regex.IsMatch(email, _
"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")
End Function
この質問はすでに回答されていますが、別のプロジェクト内にある型を持っていて、機能を追加するためにそのプロジェクトに戻りたくない場合に非常に役立つことを付け加えたいと思います。私たちは NHibernate を使用しており、クリーンな状態を維持したいデータ永続化レイヤーのプロジェクトを持っています。それらのオブジェクトに素敵で発見可能な追加メソッドを取得するために、拡張メソッドを使用することができ、それは私の一日を本当に明るくしました。
また、誰もそれを投稿していないので、MSDN にこれに関する良い記事があります - http://msdn.microsoft.com/en-us/library/bb383977.aspx
より概念的で、コードへの依存度が低い説明を追加すると思いました。
フォードが建設ラインから転がり落ちるところを想像してみてください。建設ラインにアクセスすることはできませんが、すべての Ford 車の後部に追加のスポイラーを追加できるようにしたいと考えています (展示すると見栄えが良くなります)。どうやってそれをするつもりですか?コンピューティングの世界では、Ford の工場内の元の建設ラインにアクセスできない限り、単に Ford にボルトで固定することはできません。拡張メソッドを入力します。
これで、次のようなことができます。
Ford hilux = new Ford();
hilux.DisplayRearFoiler(); // you can now do this even though you don't have access to the Ford source code.
拡張メソッドを作成する必要があります。上記の回答を参照してください。