xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

Add拡張メソッドによるコレクション初期化子

C# 3.0で導入されたコレクション初期化子をご存知の方は多いと思います。要素を追加した状態でコレクションを生成する機能です。以下のようなものです。

var languages = new List<string>
{
    "C#",
    "Visual Basic",
    "JavaScript",
};

これは次のコードの糖衣構文ですが、単一のステートメントとして表現できる点が最大のポイントです。

var languages = new List<string>();
languages.Add("C#");
languages.Add("Visual Basic");
languages.Add("JavaScript");

コレクション初期化子の独自実装

独自のコレクション型を作ることはまず滅多にないと思いますが、独自コレクションでもコレクション初期化子が利用できるよう、拡張性が確保されています。コレクション初期化子を独自実装する際の条件は以下の2点です。

  • IEnumerableインターフェースを実装していること
  • 引数のあるAdd (という名前の) メソッドを実装している

特に後者は引数の型などは規定されておらず、Addという名前ベースでコンパイラに解釈されます。所謂ダックタイピングです。以下にそのサンプルを示します。

class MyCollection : IEnumerable
{
    public void Add(object value)
    {
        //--- コレクション要素として追加するような実装をする
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main()
    {
        var collection = new MyCollection()
        {
            "Hello",
            123,
            null,
        };
    }
}

Add拡張メソッドによる独自実装

先のようにこれまでもコレクション初期化子は独自実装が可能でしたが、独自コレクション型のメンバーとしてAddメソッドを実装する必要がありました。今回、これが拡張メソッドとして実装されていてもコンパイラが検索してくれるようになりました。

class MyCollection : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

static class MyCollectionExtensions
{
    public static void Add(this MyCollection collection, object value)
    {
        //--- コレクション要素として追加するような実装をする
    }
}

class Program
{
    static void Main()
    {
        var collection = new MyCollection()
        {
            "Hello",
            123,
            null,
        };
    }
}

使うことはほぼないでしょうが、柔軟性が増えたことは嬉しい限りです。ちなみに、なぜC# 3.0当初から今まで実装されていなかったのかというと「スッカリ実装するのを忘れていた」とのことですww (VB.NETは最初からできていた)