C#のメソッドを引数に渡す方法!高階関数の基本を学ぼう
生徒
「C#でメソッドを他のメソッドに渡すことってできますか?」
先生
「はい、できますよ!C#では、メソッドを引数として渡す『高階関数』という考え方を使います。」
生徒
「メソッドを引数にするってどういうことですか?」
先生
「では、まずはその基本から一緒に学んでいきましょう!」
1. 高階関数とは?
まず「高階関数(こうかいかんすう)」という言葉について説明します。高階関数とは、メソッドを引数として受け取ったり、戻り値としてメソッドを返したりできる関数のことです。
少し難しく感じるかもしれませんが、簡単に言えば、メソッドを“道具”として別のメソッドに渡すということです。
2. メソッドを引数に渡すには?
C#では、ActionやFuncというデリゲート(delegate)を使うことで、メソッドを引数として扱うことができます。
ここで出てきた「デリゲート」とは、メソッドの形(引数と戻り値の型)を表す型のことです。
今回は、戻り値のないメソッドを引数に渡す例から見てみましょう。
3. Actionを使ってメソッドを引数に渡す
次のサンプルコードでは、Action型の引数を持つメソッドExecuteActionに、SayHelloというメソッドを渡しています。
using System;
class Program
{
static void Main()
{
ExecuteAction(SayHello);
}
static void SayHello()
{
Console.WriteLine("こんにちは!");
}
static void ExecuteAction(Action action)
{
Console.WriteLine("処理を実行します:");
action(); // 渡されたメソッドを呼び出す
}
}
このコードを実行すると、次のように表示されます。
処理を実行します:
こんにちは!
Action型は、引数なし・戻り値なしのメソッドに使えます。
4. 引数ありのメソッドを渡す方法
次は、引数ありのメソッドを渡す例を見てみましょう。引数ありのメソッドには、Action<T>やFunc<T, TResult>を使います。
using System;
class Program
{
static void Main()
{
ExecuteActionWithNumber(PrintNumber);
}
static void PrintNumber(int num)
{
Console.WriteLine($"数字は {num} です");
}
static void ExecuteActionWithNumber(Action<int> action)
{
int value = 10;
action(value); // 引数付きでメソッドを呼び出す
}
}
数字は 10 です
Action<int>は、「int型の引数を1つ受け取り、戻り値がないメソッド」を表しています。
5. 戻り値があるメソッドを渡すには?Funcの使い方
戻り値があるメソッドを渡したいときには、Funcを使います。Func<int, int>のように、最後の型が戻り値の型になります。
using System;
class Program
{
static void Main()
{
int result = CalculateSquare(x => x * x);
Console.WriteLine($"計算結果: {result}");
}
static int CalculateSquare(Func<int, int> func)
{
int input = 5;
return func(input); // 引数を渡して実行し、戻り値を受け取る
}
}
計算結果: 25
x => x * xはラムダ式と呼ばれるもので、簡単に書ける小さな関数のようなものです。もちろん、別で定義したメソッドを渡すこともできます。
6. 実生活にたとえてイメージしよう
少し難しく感じた方のために、身近な例えで考えてみましょう。
例えば、「料理を作る」プログラムがあったとして、「何を作るか?」を別の人(=メソッド)に任せたいとします。
このとき、「料理を作る」メソッドに、「カレーを作る」メソッドを渡すと、カレーが作られるようなイメージです。
つまり、「作業の流れ(枠組み)」は共通でも、「実行する中身(具体的な処理)」を自由に渡せるのがメソッドを引数にする高階関数なのです。
7. よくあるエラーと注意点
初心者の方がつまずきやすいポイントとして、以下のようなものがあります。
ActionとFuncの使い分け(戻り値があるかないか)- メソッドの引数の数や型が合っていない
();を付けてメソッドを実行してしまい、メソッドそのものではなく、戻り値を渡してしまう
特に3つ目がよくあるミスです。メソッド名だけを渡すように注意しましょう!
まとめ
今回は、C#でメソッドを引数に渡す方法、つまり「高階関数」の基本について学びました。最初は少し難しく感じるかもしれませんが、処理の流れを柔軟にコントロールできる強力な仕組みです。プログラムの中で「この部分の処理はあとで決めたい」といった場面や、「複数の処理を共通の枠組みで実行したい」ときなどに活躍します。
ActionやFuncを使えば、戻り値の有無や引数の数に応じて自由にメソッドを渡すことができるため、C#の記述力が大きく広がります。たとえば、配列やリストを操作するLINQ(リンク)機能やイベント処理でも、この高階関数の考え方は頻繁に使われており、現場のコードでも欠かせません。
また、delegateという仕組みがベースにあることも理解すると、C#の深い部分まで触れられるようになります。デリゲートは、メソッドを「値のように扱える」特別な型で、オブジェクト指向における柔軟な設計と組み合わせて使うことで、保守性や再利用性の高いコードが書けるようになります。
実際の使用例として、以下のようなコードで、「汎用的な処理の枠組み」を作り、あとから「何をするか」を差し込むことができます。
サンプル:複数の処理を切り替えて実行する高階関数
using System;
class Program
{
static void Main()
{
ExecuteWithLogging(PrintGreeting);
ExecuteWithLogging(() => Console.WriteLine("匿名関数でも実行できます!"));
}
static void PrintGreeting()
{
Console.WriteLine("こんにちは、ようこそ!");
}
static void ExecuteWithLogging(Action action)
{
Console.WriteLine("=== 開始 ===");
action(); // 渡された処理を実行
Console.WriteLine("=== 終了 ===");
}
}
=== 開始 ===
こんにちは、ようこそ!
=== 終了 ===
=== 開始 ===
匿名関数でも実行できます!
=== 終了 ===
このように、Action型の引数にメソッドやラムダ式を渡すことで、ログ処理と実行処理を分離できます。業務アプリなどでもログ記録、エラー処理、共通の前後処理などに使われています。
今後のステップとしては、引数を複数持つメソッドや、戻り値が複雑な型を扱う場合にもFuncやActionを使いこなして、より抽象化されたコードを書けるようになることが目標です。例えば、LINQのWhereやSelectなども、まさにこの考え方の延長です。
まとめると、高階関数は「処理の中身を後から差し替えたい」「動作のパターンを柔軟にしたい」プログラミングに欠かせない概念です。C#を使っていて、メソッドの引数に「処理」を渡したい場面が出てきたら、今回学んだActionやFuncの使い方をぜひ思い出してください。
生徒
「先生、メソッドを引数にできるなんて最初は想像もしてませんでした!」
先生
「慣れればとても便利なテクニックですよ。処理の流れを切り替えたり、条件によって別の処理を差し込んだりできますからね。」
生徒
「ActionやFuncを使えば、引数の有無や戻り値がある処理にも対応できるんですね。今までのメソッドの使い方と全然違って新鮮でした。」
先生
「まさに高階関数の醍醐味です。今後はLINQやイベント処理でもどんどん出てきますよ。たとえばボタンをクリックしたときの処理なんかも同じ発想です。」
生徒
「なるほど、今日の内容はこれからのC#学習でもずっと使えそうですね!」
先生
「はい、その通りです。ぜひ、サンプルをまねして書いてみて、慣れていってくださいね。」