2009年9月10日木曜日

拡張メソッド

C#3.0 から既存の型のインスタンスメソッドのように振舞う
拡張メソッドが追加されました。
使い方の一例として、String クラスにメソッドを追加してみます。

public static class StringExtensions
{
    // 指定された String オブジェクトが null
    // または Empty 文字列であるかどうかを示します。
    public static bool IsNullOrEmpty(this String s)
    {
        return String.IsNullOrEmpty(s);
    }
}

文字列の null or Empty を評価するメソッドです。
実際の呼び出し方法はこのようになります。
(StringExtensions を定義した namespace をインポートしてください。)

string s = null;
bool isNullOrEmpty = s.IsNullOrEmpty();

一見、NullReferenceException がスローされそうですが、
isNullOrEmpty 変数には true が入ります。

今度はよく使用する String.Format(String s, params object[] args) を
追加してみます。

public static class StringExtensions
{
    // String の書式項目を、指定した配列内の対応する Object インスタンスの
    // 値と等価のテキストに置換します。
    public static string Format(this String s, params object[] args)
    {
        return String.Format(s, args);
    }
}


string s = "{0} {1}".("A", "B");

変数 s には "A B" が格納されることを期待しましたが、
実際には、

インスタンス参照でメンバ 'string.Format(string, object)' に
アクセスできません。代わりに型名を使用してください。


とビルドエラーになってしまいます。

msdn によると、既存のメソッドと同じシグネチャを持つ拡張メソッドを
定義しても既存のメソッドの方が優先的にバインドされます (拡張メソッドは呼ばれません)。

参考
http://msdn.microsoft.com/ja-jp/library/bb383977.aspx
拡張メソッド (C# プログラミング ガイド)


つまり、拡張メソッドを追加した型に将来改変が加わり
同じシグネチャをもつメソッドが定義された瞬間から
拡張メソッドが呼ばれなくなってしまう危険性があるということになります。
当然ながら、同じ動きをしない可能性があります。

「ご利用は計画的に。」

1 件のコメント:

  1. public static string Format(this String s, params object[] args)のFormatを別名にすればうまくいくような。。。

    返信削除