ちょっとアリスシリーズ風に書き下し。
要は、デバッグ用に呼び出し元のクラス名を取得したいのですが、デバッグ用なので 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