ちょっとアリスシリーズ風に書き下し。
要は、デバッグ用に呼び出し元のクラス名を取得したいのですが、デバッグ用なので new 時にインスタンスやクラス名を渡したくない、のですね。なので、呼び出されたクラス/メソッドのほうから、こっそりと StackFrame を使って、呼び出し元のクラス名を取得するという技です。
' 参考
' 自分自身のクラス名とメソッド名:Gushwell's C# Dev Notes
' http://gushwell.ldblog.jp/archives/50715142.html
Public Class Form1
''' <summary>
''' アリスを作成
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim alice As New Alice
alice.Check()
End Sub
''' <summary>
''' ロリータを作成
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim lolita As New Lolita
lolita.Check()
End Sub
End Class
Public Class Person
Protected _bag As Bag
''' <summary>
''' コンストラクタ
''' </summary>
''' <remarks></remarks>
Public Sub New()
' バッグを作成(作成者名はバッグの内部で保存される)
_bag = New Bag
End Sub
''' <summary>
''' 作成者を表示
''' </summary>
''' <remarks></remarks>
Public Sub Check()
MessageBox.Show("class in " + _bag.GetClassName)
End Sub
End Class
''' <summary>
''' アリスクラス
''' </summary>
''' <remarks></remarks>
Public Class Alice
Inherits Person
End Class
''' <summary>
''' ロリータクラス
''' </summary>
''' <remarks></remarks>
Public Class Lolita
Inherits Person
' ※本来は、クラス名を渡すべき
Public Sub New()
_bag = New Bag("LOLITA")
End Sub
End Class
Public Class Bag
Protected _cname As String
''' <summary>
''' コンストラクタ
''' </summary>
''' <remarks></remarks>
Public Sub New()
Dim st As New StackTrace(False)
' Bag -> Person -> Alice の順で 2 を指定する
Dim sf As StackFrame = st.GetFrame(2)
' 呼出元を保存しておく
_cname = sf.GetMethod.ReflectedType.FullName
End Sub
''' <summary>
''' 本来はクラス名を渡すべき
''' </summary>
''' <param name="cname"></param>
''' <remarks></remarks>
Public Sub New(ByVal cname As String)
_cname = cname
End Sub
''' <summary>
''' 設定されているクラス名を取得
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function GetClassName() As String
Return _cname
End Function
End Class
Alice クラス内で、new Bag をしています。この Bag を生成したのは誰か?というのは、本来ならば Alice のインスタンスか、クラス名を渡す、あるいは、Bag プロパティに設定する、ということをやる必要があるのですが、これをスタックフレームを使って呼び出し元のクラス名を取得するようにします。
Bag クラスのコンストラクタの部分が少しトリッキーなことになっています。
Public Sub New() Dim st As New StackTrace(False) ' Bag -> Person -> Alice の順で 2 を指定する Dim sf As StackFrame = st.GetFrame(2) ' 呼出元を保存しておく _cname = sf.GetMethod.ReflectedType.FullName End Sub
StackTrace クラスでスタックトレースを取得した後、GetFrame メソッドで呼び出し元を取得します。このときに、スタックの状態が、Bag -> Person -> Alice になっているので「2」を指定しています。
間に Person クラスが挟まるのは、Alice クラスとの継承関係があるからです。なので、フォームからの呼び出しをチェックする場合も、Form クラスを継承していることを考慮にいれて、GetFrame メソッドに渡す値を調節しないといけません。ややこしいですね…というか、実装依存になるので、ピンポイントでしか使えない技です。なので、素直にクラス名を渡したほうがよさそうです。
こういう場合、XmlDocument クラスのようにファクトリーパターンを使います。コンストラクタにクラス名を渡すよりは自然かも。
Dim bag = Bag.CreateInstanceWithName("Lolita")
'あるいは
Dim bag As New Bag("Lolita")
■参考
自分自身のクラス名とメソッド名:Gushwell’s C# Dev Notes
http://gushwell.ldblog.jp/archives/50715142.html
