MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C Sharpの基礎 - デリゲートのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C Sharpの基礎 - デリゲート
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == * デリゲートとは、メソッドを参照する型である。 * LINQ等で使用される<code>Action<T></code>や<code>Func<T, TResult></code>は、デリゲート型の1つである。 * デリゲート型を作成するためだけに、クラスメソッドかインスタンスメソッドを定義するのは面倒である。 * 匿名関数を使用すれば、メソッドを定義せずにインラインに処理を記述して、デリゲート型を作成することができる。 * 匿名関数には2種類あり、その1つがラムダ式である。(正確には、C#のラムダ式はシンタックスであり、匿名関数ではない) * ラムダ式はデリゲート型の作成だけでなく、式ツリー型の生成にも使用できる。 * 匿名関数は、コンパイラがクラスメソッド・インスタンスメソッド・クラス等を内部的に作成して、それを参照するデリゲートを作っている。 <br><br> == デリゲート - Delegate型 == C#におけるデリゲートとは、メソッドを参照する型のことである。<br> <br> メソッドを参照するデリゲートを、引数として渡したり、戻り値を返している。<br> このデリゲートの存在が、LINQやReactive Extensionsを支えている。<br> <br> 全てのデリゲートは、Delegate型から派生した型である。<br> <br> デリゲート型を作成するには、以下のように<code>delegate</code>キーワードを使用する。<br> これにより、Delegate型(正確には、MulticastDelegate型)のサブクラスが定義される。<br> <syntaxhighlight lang="csharp"> // int型を引数にとり、int型を返すメソッドを参照するデリゲート型 public delegate int IntToInt(int value); // string型を引数にとり、int型を返すメソッドを参照するデリゲート型 public delegate int StringToInt(string value); // 引数が無く、int型を返すメソッドを参照するデリゲート型 public delegate int ReturnInt(); // int型を引数にとり、戻り値が無いメソッドを参照するデリゲート型 public delegate void ActionInt(int value); // 2つのint型を引数にとり、int型を返すメソッドを参照するデリゲート型 public delegate int IntIntToInt(int value0, int value1); </syntaxhighlight> <br> 次に、クラスメソッドを参照するデリゲートのインスタンスを作成する。<br> <syntaxhighlight lang="csharp"> // インスタンスを作成するデリゲート型 // int型を引数にとり、int型を返すメソッドを参照するデリゲート型 public delegate int IntToInt(int value); </syntaxhighlight> <br> <syntaxhighlight lang="csharp"> // 参照するクラスとメソッド public class Calculator { public static int AddOne (int value) { return value + 1; } } </syntaxhighlight> <br> <syntaxhighlight lang="csharp"> // デリゲートのインスタンスを作成 // AddOneメソッドを参照するIntToInt型 IntToInt addOne = Calculator.AddOne; // Calculatorクラス内ならば、以下の記述でもよい // IntToInt addOne = AddOne; </syntaxhighlight> <br> 最後に、インスタンスメソッドを参照するデリゲートのインスタンスを作成する。<br> <br> デリゲートがインスタンスメソッドを参照する場合、どのインスタンスのメソッドを参照しているかの情報が必要である。<br> デリゲートは、対象のインスタンスへの参照も内部的に保持しており、<br> そのインスタンスにアクセスするためのプロパティとして、<code>Delegate</code>型は<code>Target</code>プロパティを持っている。<br> <syntaxhighlight lang="csharp"> // インスタンスを作成するデリゲート型 // int型を引数にとり、int型を返すメソッドを参照するデリゲート型 public delegate int IntToInt(int value); </syntaxhighlight> <br> <syntaxhighlight lang="csharp"> public class Multiplier { readonly int number; public Multiplier(int number) { this.number = number; } public int Calc(int v) { return number * v; } } </syntaxhighlight> <br> MultiplierクラスのインスタンスのCalcメソッドを参照するデリゲートのインスタンスを作成するには、以下のように記述する。<br> <syntaxhighlight lang="csharp"> Multiplier doubler = new Multiplier(2); // Calcメソッドは、引数で渡した数の2倍の数を返す IntToInt doublerIntToInt = doubler.Calc; // doublerのCalcを参照するデリゲートを生成 Multiplier trippler = new Multiplier(3); // Calcメソッドは引数で渡した数の3倍の数を返す IntToInt tripplerIntToInt = trippler.Calc; // tripplerのCalcを参照するデリゲートを生成 </syntaxhighlight> <br><br> == デリゲート - Action型とFunc型 == Action<T>は、T型の引数をとり、戻り値は返さないメソッドを参照するジェネリックなデリゲート型である。<br> Func<T, TResult>は、T型の引数をとり、TResult型を返すメソッドを参照するジェネリックなデリゲート型である。<br> これらは、デリゲート型の1つである。<br> <br> 以下の例では、Func<T, TResult>型のデリゲートのインスタンスを生成している。<br> <syntaxhighlight lang="csharp"> public static int AddOne(int value) { return value + 1; } public static int GetLength(string value) { return value.Length; } public static void Main(string[] args) { // intを引数に取りintを返すAddOneメソッドを参照するデリゲートを生成 Func<int, int> addOneDelegate = AddOne; // stringを引数に取りintを返すGetLenghtメソッドを参照するデリゲートを生成 Func<string, int> GetLengthDelegate = GetLength; // doubleを引数に取りdoubleを返すSystem.Math.Absメソッドを参照するデリゲートを生成 Func<double, double> doubleFloatDelegate = Math.Abs; } </syntaxhighlight> <br> Func<T, TResult>はジェネリックなデリゲート型なので、適切に型パラメータを設定すれば、様々なメソッドを参照できます。<br> <br> Func<T, TResult>以外のジェネリクなデリゲート型には、更に多くの引数をとるAction型やFunc型のデリゲート型も存在する。<br> これらのジェネリックなデリゲート型は、Action<T>型を除き、C# 3.0 / .NET 3.5で追加された。<br> <br> 以下に、メソッドを参照することができるジェネリクなデリゲート型の例を示す。<br> * Action型 *: 引数とらず、戻り値を返さないメソッドを参照するデリゲート型 * Action<T>型 *: T型の引数をとり、戻り値を返さないメソッドを参照するデリゲート型 * Action<T1, T2>型 *: T1型、T2型の引数をとり、戻り値を返さないメソッドを参照するデリゲート型 * Func<TResult>型 *: 引数とらず、TResult型の戻り値を返すメソッドを参照するデリゲート型 * Func<T1, T2, TResult>型 *: T1型、T2型の引数をとり、TResult型の戻り値を返すメソッドを参照するデリゲート型 <br> また、Action型やFunc型以外のデリゲート型も存在する。<br> LINQ等ではAction型やFunc型が多く使用されるが、それら以外のデリゲート型もクラスライブラリに存在する。<br> <br> <code>Predicate<T></code>型というデリゲート型もその1つである。<br> このデリゲート型は、ListクラスのFindAllメソッドの引数として使用されており、ListクラスのConvertAllメソッド等でも使用されている。<br> 他のデリゲート型には、<code>Convertor<TInput, TOutput></code>型、ListクラスのSortメソッドで使用されている<code>Comparison<T></code>型等がある。<br> <br><br> == 匿名関数 == 上記に記載した通り、デリゲートはメソッドを参照する型であり、LINQ等で使用するFunc<T, TResult>型等はデリゲートの型の1つである。<br> <br> 匿名関数を説明するため、以下の例では、List<T>型とFunc<T, TResult>を引数とするCountListメソッドを記述している。<br> 第1引数であるList<T>型の変数の要素のうち、第2引数Func<T, bool>型のデリゲートを適用して、真になる要素の数を数えるメソッドである。<br> <br> 7行目の<code>predicate(element)</code>では、T型のelementを引数に、Func<T, bool>型のデリゲートであるpredicateが参照しているメソッドを呼び出している。<br> (<code>predicate(element)</code>は、<code>predicate.Invoke(element)</code>とも記述できる)<br> <syntaxhighlight lang="csharp"> public static int CountList<T>(List<T> list, Func<T, bool> predicate) { int count = 0; foreach (T element in list) { // predicateが参照するメソッドを、elementを引数に渡して呼び出す if(predicate(element)) { count++; // 真ならカウンタをインクリメント } } return count; } </syntaxhighlight> <br> 以下の例では、上記のCountListメソッドを使用して、List<string>型namesの要素のうち、文字列の長さが5未満のものを数えている。<br> <br> 匿名関数を使用しない場合、デリゲートを作成するためだけに使用するメソッドの定義は、<br> デリゲートのインスタンスを生成する場所と離れた位置に記述する必要があるため、可読性が悪い。<br> <syntaxhighlight lang="csharp"> public static bool IsLengthLessThan5(string str) { return str.Length < 5; } public static void Main(String[] args) { var names = new List<string> { "Taro", "Jiro", "Saburo" }; // IsLengthLessThan5を参照するFunc<string, bool>型のデリゲートを生成 Func<string, bool> predicate = IsLengthLessThan5; int count = CountList(names, predicate); } </syntaxhighlight> <br> 匿名関数とは、デリゲートのインスタンスを生成すると同時に、インラインでメソッドを定義するためのものである。<br> 以下の例では、上記のIsLengthLessThan5メソッドを匿名関数に変更している。<br> <syntaxhighlight lang="csharp"> public static void Main (String[] args) { List<string> names = new List<string> { "Taro", "Jiro", "Saburo" }; // 匿名関数を参照するFunc<string, bool>型のデリゲートを作成 // 匿名関数は、デリゲートの生成とメソッドの定義が近い位置にある Func<string, bool> predicate = delegate (string str) { return str.Length < 5; }; int count = CountList(names, predicate); } </syntaxhighlight> <br> 上記の例は、匿名関数の一例である。<br> 匿名関数を使用することにより、インラインで処理を記述してデリゲートを生成することができ、可読性が上がる。<br> <br> しかし、C# 3.0以降では匿名関数を使用せずに、ラムダ式を使用すべきである。<br> ラムダ式については、[[C Sharpの基礎 - ラムダ式|こちらのページ]]を参照すること。<br> <br><br> __FORCETOC__ [[カテゴリ:C_Sharp]]
C Sharpの基礎 - デリゲート
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse