0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C#のdelegateとラムダ式。型がある言語で関数を渡すには

Last updated at Posted at 2023-12-16

実装例にバグがあるので先にコメント欄を見てください。
ちゃんと理解できたら記事を直します。しょぼくてすみません...(´・ω・`)

だいぶ理解できてきたので記事を修正しました。コメントで指摘してくれたみなさまありがとうございます (*´▽`人)

JavaScriptなど形の無い言語を使っていた人が、いざC#を使うと困るのが関数をどう渡すかです。C# はデリゲートで関数を渡します。ざっくりいうと2種類あってカスタムデリゲートと汎用デリゲートがあります。
カスタムデリゲートはdelegate 構文で書きますが、デリゲートってパターンがあまりないので汎用デリゲートが.NETフレームワークのSystemに書いてあって自由に使えるから、delegate構文でカスタムデリゲートを作らなくても実装済みの汎用デリゲートでことたります。はい。

実装済みの汎用デリゲート一覧

戻り値 引数
Action<T1, T2 ...> なし T
Func<TResult> TResult なし
Func<T1, T2...T16, TResult> TResult T

実装例

// 記述の仕方
delegate int Abc(int i, int j);      // カスタムデリゲートを定義するなら...
Abc abc = new Abc(MyMethod);         // こう書くらしい...(汎用デリゲートで十分なので使わない)

Func<int, int, int> abc = MyMethod;  // 汎用デリゲートその1 3つ目の変数は戻り値です
Action<int, int> abc = MyMethod;     // 汎用デリゲートその2 戻り値なしだとこう書く
// 実装例
using System;

public class Program {
    static Action<int, int> hello;  // 引数を2つとる汎用デリゲートの hello を用意
    public static void Main(string[] args) {
        hello = HelloBirthday;
        hello(10, 20);
    }
    public static void HelloBirthday(int month, int day) {
        Console.WriteLine($"Hello world {month}/{day}. HappyBirthday!");
    }
    // その他の記念日
    // public static void HelloOtherAnniversary(int month, int day) { ...
}

こうすると関数を参照できますね ^^

匿名メソッドも使えます。
戻り値の型はreturnの値から暗黙型変換され、できなければエラーになります。

// <c#1.0の実装例>: 汎用デリゲートも匿名メソッドも無理なのでカスタムデリゲートとクラスメソッドです
using System;
public class Program {
    public delegate void HelloDlg(int month, int day); // クラスの一部になるのでstatic利用可
    public static HelloDlg hello;
    public static void Main(string[] args) {
        hello = new HelloDlg(HelloBirthday);
        hello(10, 20);
    }
    public static void HelloBirthday(int month, int day) {
        Console.WriteLine($"Hello world {month}/{day}. HappyBirthday!");
    }
}

// <C#2.0 実装例>:C#2.0では汎用デリゲートも匿名メソッドも使えます
using System; 
public class Program {
    static Action<int, int> hello;
    public static void Main(string[] args) {
        hello = delegate (int month, int day) {
            Console.WriteLine($"Hello world {month}/{day}. HappyBirthday!");
        };
        hello(10, 20);
    }
}

//<C#3.0 実装例>:C#3.0ではさらに省略してラムダ式にできます。
using System; 
public class Program {
    static Action<int, int> hello;
    public static void Main(string[] args) {
        hello = (int month, int day) => {
            Console.WriteLine($"Hello world {month}/{day}. HappyBirthday!");
        };
        hello(10, 20);
    }
}

またイベントも実装できます。Delegate型で定義するのですがイベントのメソッドは +, -, +=, -= で追加/削除でき、イベントに追加したデリゲートメソッドはすべて実行されます。

// カスタムデリゲートでイベントを書くとこう(汎用デリゲートとラムダ式のが楽だね)
public delegate void HelloDlg(int month, int day);
event HelloDlg hello = new HelloDlg(HelloBirthday) + new HelloDlg(HelloAnniversary)
hello += new HelloDlg(HelloHappyNewYear);

hello(1,1); // HappyBirthday と HelloAnniversary と HelloHappyNewYear が実行される(順不同)
            // ※この3つのメソッド全部書くと長くなるので省略しました
// 汎用デリゲートとラムダ式で書いてもいい
void Output(int month, int day, string msg) {
    Console.WriteLine($"Hello world {month}/{day}. {msg}!");
}
event Action<int, int> hello = (int month, int day) => { Output(month,day,"HappyBirthday"); };
hello += (int month, int day) => { Output(month,day,"FirstAnniversary"); };
hello += (int month, int day) => { Output(month,day,"HappyNewYear"); };
hello += (int month, int day) => { Output(10,31,"HappyHalloween"); };
    
hello(1,1); // HappyBirthday と FirstAnniversary ... と4つ実行される(順不同)

イベントを持つクラスを作ると外部からはイベントの追加/削除だけ、内部でタイミングを見てイベントを実行する動き方をします。
これらを前提にしつつもC#のゲーム製作のUnityだとまた別の仕組みで連携してます。Invokeとか、UniTaskとかそちらは別の記事でおいおい解説するかも...。

参考元

C++をさわったことある人向けのわかりやすい解説記事

0
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?