画像ファイル
画像ファイル デリゲート入門
VB.NET C#全般
1羊の皮を着た狼 VB.NET
2Form1、Form2の相互参照
3Form1、Form2の相互参照 2
4VB.NET C# データ型の基本
5VB.NET C# 文字列
6VB.NET タイマー精度
7BackgroundWorkerの魅力1..
8BackgroundWorkerの魅力2..
9VB6のタイマー
10コントロールの配列をインデクサ..
11コントロールの配列はジェネリク..
12インデクサ(C#、VB.NET)
13インデクサでBit操作
14Unicode 入門
15デリゲート入門
16マルチスレッド入門
17イベント入門
18デリゲートとイベント
18インターフェースの基本

RichTextBox関係
1RichTextBoxの不思議
2テキスト色付け高速化計画
3VB.NET RichTextBox1
4VB.NET RichTextBox 2

RS-232C関係
1RS-232Cの基礎
2RS-232Cの何が変わった..
3SerialPortクラス
4Unicode(ユニコード)の壁
5マルチスレッドの壁
6RS-232C サンプルコード
7RS-232CのHEXモニタ
8RS-232C 送信モジュール
9RS-232Cのループテスト
10RS-232Cのピンチェンジ..

Socket通信
1C#、VB2005 でSocket通信
2サーバー 複数接続

プロセス間通信
1プロセス間通信(送信側)
2プロセス間通信(受信側)


質問、意見はこちらに
画像ファイル

昔のPCのコーディング
世界初の8 bitマイクロプロセッサはIntelの8008と言うチップでプログラムは数字の羅列の
機械語で書いていました。
ジャンプ命令などは飛び先のメモリの番地を直接書くわけです。
この為プログラマは常に紙に書いたメモリマップを持っていました。
そのうちにニーモニックなるものが出てきて、数字の羅列の機械語から命令などは
より人間にわかり易いアルファベットによる文字になりました。
ジャンプ先などの番地も数字でアドレスを書くのではなく、文字によるラベルが使えるように
なりプログラミングの作業性が一段と向上しました。
文字やラベルはアッセンブラと呼ばれるプログラムがCPUが理解できる機械語に直すのです。

デリゲートはメソドの参照を保持する
C#やVB.NETでメソドと呼ばれる物はプログラムの塊でメモリー上の何処かに有ります。
メソドを呼び出すと言うことは機械語で言えばジャンプ命令が行われると言うことです。
ただしFrameWorkのプログラマはそのメソドがメモリー上の何処に有るかなどということは知らなくても良いのです。
番地に相当する名前を書くだけでメソドを呼び出すことがジャンプ命令などと夢にも思っては居ません。
現代のプログラマにとってはジャンプ命令は禁句でジャンプ命令は構造化の敵なのです。
さてデリゲートですが、デリゲートはメソドの参照を持つクラスです。
参照とは平たく言うとアドレスです。
つまりデリゲートは名前でなくメソドをアドレスで呼び出すことの出来るクラスなのです。
回りまわって又昔に戻ったのです。
クラスに有るメソドの参照を(アドレス)をデリゲートに登録しておくと、そのメソドを
デリゲートで呼び出すことが出来るのです。
厳密にはデリゲートが保持するのはクラスのインスタンスのメソドの参照です。

なぜアドレスで呼び出すのか?
何故せっかく名前で呼び出せるものを又昔の様にアドレスで呼び出そうとするので有ろうか。
例えばある大きなファイルを読み書きする時その処理をメインスレッドで行うと、
読み書きしている間スレッドが固まってしまいます。
これを避けるために、通常読み書きはメインスレッドとは別のスレッドを作成して、非同期に
操作が行われます。
こうするとメインスレッド上で他の作業の継続が可能になるのです。
ただし多くの場合呼び出し側のスレッドでも読み書きの終了や、読み込んだファイルの内容が
知りたい場合が有ります。
つまり読み書きを指示したスレッドの指定したメソドに読み書きをしているスレッドから報告(コールバック)
が欲しいのです。
それには新しく作成された読み書きを行うスレッドに対して、ここに通知しなさいという何らかの情報を渡す
必要があります。
この為に使われるのが通知すべきメソドのアドレスです。
確かにメソドの名前を渡す方法も考えられるが、読み書きを行うスレッドを作成したスレッドも複数の
インスタンスを持っている可能性が有り、名前を渡す場合は何らかの方法でインスタンスを区別
しなければなりません。
アドレスは複数のインスタンスが有ってもインスタンス毎に異なります。
すなわちアドレスを使うと、目的のインスタンスのメソドを確実に渡すことが出来ます。
この考え方はC#やVB.NETのイベントの方法にも取られています。
イベントもデリゲートそ使って行われるのです。

デリゲートのプロトタイプ宣言
ただしデリゲートが単純にメソドのアドレスを保持していて、そのアドレスにジャンプしただけでは
不具合が生じます。
メソドには引数を取るものや戻り値を返すものが有からです。
そこで目的のメソドのアドレスを保持することが出来るデリゲートクラスは必ずそのメソドと同じ
戻り値や引数を設定できる方法で宣言します。(デリゲートのプロトタイプ宣言)。
コンパイラはそのプロトタイプを見て、そのデリゲートが目的のメソドの引数や戻り値にマッチ
しているか否かを確認し安全性を保障します。
もしそれが一致していなければビルド時にエラーを報告するはずです。
つまりデリゲートは単にクラスのインスタンスのメソドのアドレスを保持するだけではなく
引数と返値の受け渡しも行なうのです。

デリゲートの実際例
実際のデリゲートを見てみましょう。
delegate void dlgWriteString(string msg); ---C#
Delegate Sub dlgWriteString(ByVal msg As String)---VB2005
これは文字列を引数に取り返値を取らないデリゲートのクラスの宣言である(プロトタイプ)です。
このデリゲートクラスは同じ引数を持ち同じ返値を持つメソドであればどの様なメソドで有っても
その参照(アドレス)を保持できます。
このデリゲートを使って
C#のコード
public void WriteMessage(string msg)
{
Console.WriteLine(msg);
}
}

VB2005のコード
Class WriteToScreen
Public Sub WriteMessage(ByVal msg As String)
Console.WriteLine(msg)
End Sub
End Class
このクラスのWriteMessageメソドを呼び出してみます
デリゲートはクラスで有る為インスタンスを作り、コンストラクタには保持すべきクラスのインスタンスの
メソドを指定します。
C#のコード
dlgWriteString dws = new dlgWriteString(ws.WriteMessage);
VB2005のコード
Dim dws As New dlgWriteString(AddressOf ws.WriteMessage)
デリゲートを実行するには
dws(msg);
dws(msg)
とすれば良いのです。

Action<T>
さてデリゲートの宣言(プロトタイプ)ですが
FrameWorkには既定の宣言(既に行われている)が有ります。
Action<T>と呼ばれるもので1つの引数と戻り値が無いデリゲートが宣言されています。
(Action<T>はFrameWork2.0以上で使用できる。FrameWork3.0以上では更に色々な既定のデリゲートが有る。)
<T>のTにはタイプが入る、上のデリゲートは
C#のコード
Action<string> wm = new Action<string>(ws.WriteMessage);
	

VB2005のコード
Dim wm As New Action(Of String)(AddressOf ws.WriteMessage)
	
となります
delegate void dlgWriteString(string msg); --- C#
Delegate Sub dlgWriteString(ByVal msg As String) ---VB2005
のプロトタイプは必要なくなります。

デリゲートと匿名メソド
さてもう少し進めよう、C#には匿名メソドと言うものが有る(残念ながらVB2005には無い)。
public void WriteMessage(string msg)
{
   Console.WriteLine(msg);
}
はWriteMessageという名前を持っています。
匿名メソドとはこの名前を持たないメソドです。
これを使うと
delegate void dlgAwrite();
と引数を持たないデリゲートを宣言して、
dlgAwrite da = delegate() {Console.WriteLine(msg);};
da();
の様にインラインでメソドを使用することが可能となります。
この匿名メソドによるデリゲートそれが実行されるクラスのスコープを持つために
引数の省略ができてオーバーヘッドが少ない事とデリゲートの為のメソドが同じ場所に
書かれて居る為にコードが見やすい利点があります。

C#のコード

using System;
using System.Collections.Generic;
using System.Text;

namespace DlegateTest
{
delegate void dlgWriteString(string msg);
delegate void dlgAwrite();

//デリゲートで呼ばれるメソドを持つクラス
class WriteToScreen
{
//デリゲートで呼ばれるメソド
public void WriteMessage(string msg)
{
Console.WriteLine(msg);
}
}

class Program
{
static void Main(string[] args)
{
string msg = "Hello World!";

//これはデリゲートとは関係無い普通の呼び出し
WriteToScreen ws = new WriteToScreen();
ws.WriteMessage(msg);

//デリゲートのインスタンスを作成して
//WriteToScreenの WriteMessageの
//インスタンスのアドレスを登録する
dlgWriteString dws = new dlgWriteString(ws.WriteMessage);
//デリゲートの呼び出し
dws(msg);

//FrameWorkで宣言済みのActionデリゲートを使う
Action<string> wm = new Action<string>(ws.WriteMessage);
wm(msg);

//匿名メソドを使用したデリゲート
dlgAwrite da = delegate() {Console.WriteLine(msg);};
da();
}
}

}

VB2005のコード
Imports System
Imports System.Collections.Generic
Imports System.Text

Module Module1

Delegate Sub dlgWriteString(ByVal msg As String)
Sub Main()
Dim msg As String = "Hello World!"
'これはデリゲートとは関係無い普通の呼び出し
Dim ws As New WriteToScreen()
ws.WriteMessage(msg)

'デリゲートのインスタンスを作成して
'WriteToScreenのWriteMessageの
'インスタンスのアドレスを登録する
Dim dws As New dlgWriteString(AddressOf ws.WriteMessage)
dws(msg)
'FrameWorkで宣言済みのActionデリゲートを使う
Dim wm As New Action(Of String)(AddressOf ws.WriteMessage)
wm(msg)

End Sub
End Module
'デリゲートで呼ばれるメソドを持つクラス
Class WriteToScreen
'デリゲートで呼ばれるメソド
Public Sub WriteMessage(ByVal msg As String)
Console.WriteLine(msg)
End Sub
End Class



ブログ  デリゲート も合わせてお読みください。
画像ファイル