■Action<T>デリゲートを使用するメソッド
Action<T>デリゲートのようなジェネリック・デリゲートがクラス・ライブラリでわざわざ定義されているのは、当然ながらそのデリゲートを使用しているメソッドが存在するためです。
List<T>ジェネリック・クラス(VBの場合にはList(Of T)ジェネリック・クラス、以下List<T>クラスと省略)のForEachメソッドは、Action<T>デリゲートを使用するメソッドの1つです。このメソッドのシグネチャは次のようになっています。
void ForEach(Action<T> action)
Sub ForEach(action As Action(Of T))
このメソッドは、コレクション(List<T>オブジェクト)内に格納されている要素の1つ1つに対して、パラメータで指定されたデリゲートを呼び出してくれるメソッドです。
以下にList<T>クラスのForEachメソッドを使ったサンプル・プログラムを示します。
using System;
using System.Collections.Generic;
class GenericSample {
void MyAction(string s) {
Console.WriteLine(s);
}
void Sample() {
List<string> stringList = new List<string>();
stringList.Add("こんにちは");
stringList.Add("さようなら");
// デリゲート・インスタンスの作成
Action<string> myActionDelegate = new Action<string>(MyAction);
stringList.ForEach(myActionDelegate);
// 出力:
// こんにちは
// さようなら
}
static void Main() {
GenericSample gs = new GenericSample();
gs.Sample();
}
}
Imports System
Imports System.Collections.Generic
Class GenericSample
Sub MyAction(ByVal s As String)
Console.WriteLine(s)
End Sub
Sub Sample()
Dim stringList As New List(Of String)
stringList.Add("こんにちは")
stringList.Add("さようなら")
' デリゲート・インスタンスの作成
Dim myActionDelegate As Action(Of String) = AddressOf MyAction
stringList.ForEach(myActionDelegate)
' 出力:
' こんにちは
' さようなら
End Sub
Shared Sub Main()
Dim gs As New GenericSample()
gs.Sample()
End Sub
End Class
stringListオブジェクトの各要素に対して、MyActionメソッドが呼び出され、その値が表示されるのが分かります。
これまでコレクションの各要素を処理するには、順に要素を取り出し、それから処理するというのが一般的なスタイルでした。.NET Framework 2.0のクラス・ライブラリでは、デリゲートを活用することにより、各要素を処理するためのメソッド(の参照)をコレクションに渡しておき、各要素についてそのメソッドを呼び出させる、というスタイルが導入されたといえるでしょう。
■C# 2.0におけるデリゲート・インスタンス作成部分の簡略化
ところで、デリゲートのインスタンスを作成するのには、上記のサンプル・プログラムにもあるように、VBでは「AddressOf演算子」でメソッド名を指定するだけなのに対して、C#では「new」が必要で記述が少し冗長になりがちでした。
しかしC# 2.0では、以下のようにnew以降の部分をバッサリと省略して、いきなりメソッドを代入できるようになりました*。
Action<string> myActionDelegate = new Action<string>(MyAction);
↓↓↓
Action<string> myActionDelegate = MyAction;
* この機能はメソッド・グループ変換(method group conversions)と呼ばれます。
デリゲート・インスタンス用の変数(上記のサンプル・プログラムでは「myActionDelegate」)も使うのをやめれば、上記のプログラムは次のようにだいぶすっきりします。
using System;
using System.Collections.Generic;
class GenericSample {
void MyAction(string s) {
Console.WriteLine(s);
}
void Sample() {
List<string> stringList = new List<string>();
stringList.Add("こんにちは");
stringList.Add("さようなら");
// デリゲートとしてメソッド名を直接指定
stringList.ForEach(MyAction);
// 出力:
// こんにちは
// さようなら
}
static void Main() {
GenericSample gs = new GenericSample();
gs.Sample();
}
}
【コラム】 クラス・ライブラリのメソッドをデリゲートに使う
C#にはforeach文、VBにはFor Each文があるため、通常はForEachメソッドをわざわざ使う必要性はそれほどないかもしれません。
ただし少しトリッキーですが、上記のサンプル・プログラムに限れば、Console.WriteLineメソッドを呼び出しているMyActionメソッドに対してデリゲートを作成するのではなく、クラス・ライブラリのConsole.WriteLineメソッドに対して直接デリゲートを作成することでプログラムはすごくシンプルになります。
using System;
using System.Collections.Generic;
class GenericSample {
void Sample() {
List<string> stringList = new List<string>();
stringList.Add("こんにちは");
stringList.Add("さようなら");
// Console.WriteLineをデリゲートとして指定
stringList.ForEach(Console.WriteLine);
// 出力:
// こんにちは
// さようなら
}
static void Main() {
GenericSample gs = new GenericSample();
gs.Sample();
}
}
Imports System
Imports System.Collections.Generic
Class GenericSample
Sub Sample()
Dim stringList As New List(Of String)
stringList.Add("こんにちは")
stringList.Add("さようなら")
' Console.WriteLineをデリゲートとして指定
stringList.ForEach(AddressOf Console.WriteLine)
' 出力:
' こんにちは
' さようなら
End Sub
Shared Sub Main()
Dim gs As New GenericSample()
gs.Sample()
End Sub
End Class
ジェネリック・デリゲートをパラメータに取るメソッドを次にもう1つ見てみましょう。
Copyright© Digital Advantage Corp. All Rights Reserved.