しらとりのブログ

社会人ひよこプログラマのtil

メソッドグループとは

int→string変換のコードを書きます。

int i = 10;
string s = i.ToString;

このコードは以下のコンパイルエラーが出ます。

CS0428 メソッド グループ 'ToString' を非デリゲート型 'string' に変換することはできません。このメソッドを呼び出しますか?

上記のコードはToStringメソッドに()をつけ忘れただけの単純なエラーです。ですがエラーメッセージにはなんやら聞きなれないキーワードがいくつか出てきます。これは何を言っているのか考えてみます。

メソッドグループ

メソッド グループ 'ToString' を~の部分を考えます。どうやらToStringは"メソッドグループ"というものらしいです。本来ToStringメソッドと認識されるべき箇所ですが誤って括弧をつけ忘れたためメソッドグループと認識されてしまっているようです。

これは、メソッドのオーバーロードの仕組みに関係しています。オーバーロードは同じ名前で引数の異なるメソッドを定義できる機能で、メソッド名というくくりでは複数のメソッドが存在する可能性があります。このオーバーロードを含めたメソッドの集まりをメソッドグループと呼んでいます。

とどのつまり、C#ではメソッド名のことをメソッドグループと明確に定義して呼ぶようになっています。

メソッドグループ変換

次に、非デリゲート型 'string' に変換することはできません。を考えます。 "変換することができません"からキャストエラーであることが読み取れます。さらに、"非デリゲート型"というサジェストから代入されようとしている右辺のメソッドグループがデリゲート型に変換できることを示しています。
つまり括弧の付け忘れでこのようなエラーメッセージが出るのは、メソッドグループをデリゲートに変換できる機能をC#が持っているから、ということになります。

メソッドグループ変換の例

下記のコードはMVVMでよくみられるDelegateCommand実装もどきです。

class Program
{
    static void Main(string[] args)
    {
        // Action<T>型にメソッドグループを渡している
        var command1 = new DelegateCommand<int>(hoge);
        var command2 = new DelegateCommand<double>(hoge);

        command1.Execute(1); // hoge(int)
        command2.Execute(2d); // hoge(double)
    }

    static void hoge(int i){ Console.WriteLine("hoge(int)"); }
    static void hoge(double i) { Console.WriteLine("hoge(double)"); }
}

class DelegateCommand<T>
{
    Action<T> _action;
    public RelayCommand(Action<T> action)
    {
        this._action = action;
    }
    public void Execute(object parameter)
    {
        this._action((T)parameter);
    }
}

ポイントはAction型(1つのパラメーターを受け取り、戻り値を持たない汎用のデリゲート)を引数に受けるDelegateCommandのコンストラクタでメソッドグループを指定できるところです。この例ではProgram.hogeメソッドに2つのオーバーロードを定義してからメソッドグループを渡しています。このとき、DelegateCommandに指定された型(Tの部分)をもとにオーバーロードが解決されてどちらかのメソッドがデリゲートに格納されます。