AddressOfで指定する関数名を、文字列で指定したい

解決


コアラ  2006-04-29 08:51:14  No: 131192

こんにちわ。

VB.NETで開発をしているのですが、
どなたかやり方を知っていたら教えていただけないでしょうか?

こんなことがやりたいのですが、
AddHandler button1.click, AddressOf button1_click
AddHandler button2.click, AddressOf button2_click
AddHandler button3.click, AddressOf button3_click
AddHandler button4.click, AddressOf button4_click

このままだと、あまりかっこよくないので、以下のように出来たら
うれしいのですが、これを実現する方法って何かあるのでしょうか?

Dim controlArray() As string = {button1, button2, button3, button4}
Dim myObj As object
Dim myObjName As String

For Each myObjName In controlArray
  For Each myObj In Me
    if myObj.Name = myObjName then
      AddHandler myObj.click, AddressOf myObjName & "_click" ' ← こんなことはできないけど、何か方法があればうれしいっす。 
    endif
  next
next

つまり、AddressOfで指定する関数名を、文字列で指定したいのです。

どなたかご助言お願いいたします。


魔界の仮面弁士  2006-04-30 01:44:45  No: 131193

> このままだと、あまりかっこよくないので、
そうですか? 文字列指定だと、コンパイル時にチェックができないので、
むしろかっこ悪い気もしますが……まぁ、個人の主観にもよりますしね。(^^;

> AddHandler button1.click, AddressOf button1_click
こちらでは、「button1」は System.Windows.Forms.Button 型なのに、

> Dim controlArray() As string = {button1, button2, button3, button4}
こちらでは、「button1」が String 型であるかのように見えますが、記述ミスでしょうか?

> つまり、AddressOfで指定する関数名を、文字列で指定したいのです。
たとえば、こんな感じで書く事ができます。

'下記4メソッドは、意図的に Handles 句をつけずに宣言してあります。
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
  MessageBox.Show("Click1")
End Sub
Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs)
  MessageBox.Show("Click2")
End Sub
Private Sub Button3_Click(ByVal sender As Object, ByVal e As EventArgs)
  MessageBox.Show("Click3")
End Sub
Private Sub Button4_Click(ByVal sender As Object, ByVal e As EventArgs)
  MessageBox.Show("Click4")
End Sub

'チェックボックスのon/offで、イベントハンドラの関連付けを登録/解除します。
Private Sub CheckBox1_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) Handles CheckBox1.CheckedChanged
  Dim Buttons() As Button = {Button1, Button2, Button3, Button4}
  Dim UseEvent As Boolean = CheckBox1.Checked

  Dim BF As BindingFlags  'メソッドの検索条件
  BF = BF Or BindingFlags.DeclaredOnly  '継承元のメンバを含めない
  BF = BF Or BindingFlags.NonPublic     '非Publicメソッドを含める
  BF = BF Or BindingFlags.Instance    'インスタンスメソッドを含める
  '今回は、下記の条件は含めない
  'BF = BF Or BindingFlags.Public     'Publicメソッドを含める
  'BF = BF Or BindingFlags.Static     'Sharedメソッドを含める
  Dim Methods() As MethodInfo = Me.GetType().GetMethods(BF)

  For Each M As MethodInfo In Methods
    Dim MethodName As String = M.Name
    For Each B As Button In Buttons
      If StrComp(MethodName, B.Name & "_Click", CompareMethod.Text) = 0 Then
        Dim D As [Delegate]
        D = [Delegate].CreateDelegate(GetType(EventHandler), Me, MethodName)
        If UseEvent Then
          AddHandler B.Click, DirectCast(D, EventHandler)
          Trace.WriteLine("AddHandler:" & MethodName)
        Else
          RemoveHandler B.Click, DirectCast(D, EventHandler)
          Trace.WriteLine("RemoveHandler:" & MethodName)
        End If
        Exit For
      End If
    Next
  Next
End Sub


魔界の仮面弁士  2006-04-30 02:21:19  No: 131194

少し補足。上記から、コアとなる部分だけ取り出すと、下記の3行だけで書けます。

For Each B As Button In New Button() {Button1, Button2, Button3, Button4}
  AddHandler B.Click, DirectCast([Delegate].CreateDelegate(GetType(EventHandler), Me, B.Name & "_Click"), EventHandler)
Next

先の例でリフレクションが使われているのは、Sub Button1_Click などが
定義されているか、その存在チェックを行っているためです。
(厳密に行うなら、メソッド引数のチェックなども必要ですけれどね)


コアラ  2006-05-02 23:21:32  No: 131195

魔界の仮面弁士さん。
ありがとうございます。

教えていただいた方法で、無事、実現できました。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加