【C#】Actionを定義して使用する方法

以前に「【C#】Predicateを定義して使用する方法」の記事ではデリゲートからの派生形である「Predicate」を学習しました。今回は「Predicate」の仲間である「Action」を解説していきます。「Predicate」は戻り値がbool型でしたが、今回の「Action」は戻り値を持たない void 型になります。実際のサンプルコードも紹介しながら解説していきます。
Actionとは
実際のサンプルソースの前にActionの特徴から確認していきましょう。Actionは以下の特徴を持っているC#の機能となります。
- 戻り値を持たないvoid型である
- Genericで引数の型を指定できる
- パラメータは最大16個まで設定できる
例えばint型の引数を1つだけ受ける場合は以下のように記述します。
Action HogeAction = ...
また、パラメータを複数指定する場合はカンマ区切りで後ろに付け加えていくだけです。また違う型で引数を受け取ることも可能になります。
Action<int, string, bool> HogeAction = ...
上記のような場合は第一引数がint型、第二引数がstring型、第三引数がbool型を受けることができます。ここまでがActionの基本事項となります。
C#でActionを書く方法(単一の引数の場合)
それでは実際にActionを使ったアプリケーションを作成していきます。新規のコンソールアプリケーションを作成して以下のソースコードを記述して実行してみてください。
using System;
using System.Collections.Generic;
namespace App01
{
class Program
{
static void Main(string[] args)
{
//リストを作成する
var list = new List()
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
};
//メソッドに処理を渡して実行する
WriteNumbers(x =>
Console.WriteLine($"数値は{ x }です。"),
list);
Console.ReadLine();
}
private static void WriteNumbers(Action action,
List storage)
{
foreach(int item in storage)
{
//渡されたactionを実行する
action(item);
}
}
}
}
上記のアプリケーションのうち、Actionを定義している箇所は以下の箇所になります。int型の引数を一つ受け取れるActionを定義しています。
private static void WriteNumbers(Action action, List storage)
第二引数は単純にint型のリストになります。第一引数のほうがActionなのは見てわかる通りです。ではこの第一引数が使用されているメソッド内をみてみます。
foreach(int item in storage)
{
//渡されたactionを実行する
action(item);
}
第二引数で受け取ったリストをforeachで回しつつ、第一引数であるActionを実行しています。第二引数はint型のリストですので、各要素はint型になります。よって「action(item)」が成り立ちます。またvoid型ですので戻り値はありません。
では、このActionが定義されている箇所をみてみます。実際は「WriteNumbers」メソッドの呼び出し元にラムダで記述しています。対応するのは以下の箇所です。
//メソッドに処理を渡して実行する
WriteNumbers(x =>
Console.WriteLine($"数値は{ x }です。"),
list);
横に長くなってしまい見づらいので引数を改行しています。ラムダ式だけを抜き取ると以下のようになります。
x => Console.WriteLine($"数値は{ x }です。")
第一引数のActionはint型の引数を1つ取ることができます。ラムダ式は「(引数) => (式)」で表すことができ、引数が一つの場合は括弧を省略できるので「x => (式)」としています。
また、上記のラムダ式は処理部分の内容が「Console.WriteLine($”数値は{ x }です。”)」となっており、引数をそのままコンソール画面に出力するだけの処理をしています。
なお、この引数である「x」は「WriteNumbers」メソッド内の「action(item);」と記述された「item」が該当します。このitemはint型のリスト(storage)の各要素ですので、int型の値になります。具体的には「1, 2, 3, 4, 5, 6, 7, 8, 9, 10,」の各要素です。
なお匿名メソッドでも記述できますので、以下を参考までに掲載しておきます。Predicateでもそうでしたが、Actionもデリゲートのテンプレートみたいなものですので匿名メソッドで記述可能です。
WriteNumbers(delegate (int x)
{
Console.WriteLine($"数値は{ x }です。");
},
list);
C#でActionを書く方法(複数の引数の場合)
先ほどは単一の引数の場合のActionについて学びました。次は複数の引数を持つ場合のActionのサンプルコードを見ていきたいと思います。複数の引数は最大16個まで持つことができますが、一般的には16個も引数を持つことは稀だと思いますので2個くらいにとどめたいと思います。
では、新規のコンソールアプリケーションを作成して以下のソースコードを記述してみてください。記述ができたら、実際に動かしてみて挙動を考えてみましょう。
using System;
using System.Collections.Generic;
namespace App02
{
class Program
{
static void Main(string[] args)
{
//処理で使用する値を取得する
Console.WriteLine("数値を入力してください。");
int input = Convert.ToInt32(Console.ReadLine());
List storage = new List()
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
};
//メソッドを実行する
WriteNumbers((src, num) =>
{
foreach(var item in src)
{
if(item.Equals(num))
{
Console.WriteLine("入力値は存在します。");
return;
}
}
Console.WriteLine("入力値は存在しません。");
},
storage,
input);
Console.ReadLine();
}
//Actionを起動させるメソッド
private static void WriteNumbers(Action<List, int> action,
List storage,
int input)
{
//第一引数と第二引数を渡して処理を実行する
action(storage, input);
}
}
}
前の章で詳しく解説しているので、ここでは詳細な説明を割愛して、簡単な説明のみにとどめたいと思います。Actionを定義しているのは「WriteNumbers」メソッドになります。
//Actionを起動させるメソッド
private static void WriteNumbers(Action<List, int> action,
List storage,
int input)
引数を三つ取得することができ、一つ目がActionの処理、二つ目がActionに渡す引数の一つ目、また第三引数がActionに渡す二つ目の引数となります。処理内部では「action(storage, input);」と引数を渡して実行するだけです。
なお、複数の引数を持つ場合は「Action<List, int> action」と引数の型をカンマ区切りで設定することができます。今回はint型のリストとint型の数値を受け取るようにしています。Actionを定義しているのは以下の箇所になります。
//メソッドを実行する
WriteNumbers((src, num) =>
{
foreach(var item in src)
{
if(item.Equals(num))
{
Console.WriteLine("入力値は存在します。");
return;
}
}
Console.WriteLine("入力値は存在しません。");
},
storage,
input);
WriteNumbersメソッドでは第一引数がActionであり、処理内容になります。今回は複数行を記述できるラムダ式の形式で記載しています。引数は「(src, num)」としていますが、これは「WriteNumbers」メソッドの「action(storage, input);」に該当します。一つ目がint型のリスト、二つ目の引数がint型の数値でした。
以上がActionを定義する方法でした。サンプルでも解説したので、そこまで難しい内容ではなかったのではないでしょうか。LINQを理解するうえで重要になるので、復習も忘れずにしておいてください。