lundi 19 juin 2017

Accessing variables thru reflection

I have a Windows Forms solution written in VB.NET. Using reflection from the Module MOD1 I want get/set public variable of Module MOD2. A strong constraint is to use just strings, as a command line interpreter would do. Here following there is the code I used to recreate the failing environment.

While accessing simple variable (useDialog) this code behaves as expected, but some problems rise while accessing complex variable (fWin or MainForm). I've made some mistake, but I don't realize which one!

Please note: fWin is a Windows Forms class.

Public Class fWin
    Public BoolValue As Boolean = True
    Public FileRoot As String = ""

    Private Sub fWin_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        mod1.MainForm = Me
        FileRoot = "My file root"
        mod2.Change()
    End Sub
End Class

Module mod1
    Public useDialog As Boolean
    Public PathRoot As String = "My path root"
    Public MainForm As fWin
End Module

Imports System.Reflection
Module mod2
    Dim currAssembly As Assembly = Assembly.GetExecutingAssembly()

    Public Function MemberSearch(memPathName As String, ByRef oParents() As Object) As Boolean
        Dim mcName() As String = memPathName.Split(".")
        Dim imc_scan As Integer
        Dim m_scan, currModule As [Module]
        Dim t_scan, currType As Type
        Dim f_scan, currField As FieldInfo
        Dim LoP As List(Of Object)

        currModule = Nothing
        currType = Nothing
        currField = Nothing
        LoP = New list(Of Object)
        Array.Resize(oParents, 0)

        imc_scan = 0
        For Each m_scan In currAssembly.GetModules()
            If (System.IO.Path.GetFileNameWithoutExtension(m_scan.Name) = mcName(imc_scan)) Then
                LoP.Add(m_scan)
                currModule = m_scan
                Exit For
            End If
        Next
        If (currModule Is Nothing) Then
            oParents = LoP.ToArray()
            Return False
        End If
        If (imc_scan >= (mcName.Length - 1)) Then
            oParents = LoP.ToArray()
            Return True
        Else
            imc_scan += 1
            For Each t_scan In currModule.GetTypes()
                If (t_scan.Name = mcName(imc_scan)) Then
                    LoP.Add(t_scan)
                    currType = t_scan
                    Exit For
                End If
            Next
            If (currType Is Nothing) Then
                oParents = LoP.ToArray()
                Return False
            Else
                If (imc_scan >= (mcName.Length - 1)) Then
                    oParents = LoP.ToArray()
                    Return True
                End If

                Dim bf As BindingFlags = BindingFlags.Instance Or BindingFlags.Static Or BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.IgnoreCase

                While (currType IsNot Nothing) AndAlso currType.IsValueType = False And (imc_scan < (mcName.Length - 1))
                    imc_scan += 1
                    currField = Nothing
                    For Each f_scan In currType.GetFields(bf)
                        If (String.Compare(f_scan.Name, mcName(imc_scan), True) = 0) Then
                            LoP.Add(f_scan)
                            currField = f_scan
                            Exit For
                        End If
                    Next
                    If currField Is Nothing Then
                        oParents = LoP.ToArray()
                        Return False
                    Else
                        Try
                            Dim Container As Object = LoP.Last
                            If (imc_scan >= (mcName.Length - 1)) Then
                                Container = LoP(LoP.Count - 2)
                            End If
                            currType = Container
                        Catch ex As Exception
                            currType = Nothing
                        End Try
                    End If
                End While
            End If
        End If

        oParents = LoP.ToArray()
        Return (imc_scan <= (mcName.Length - 1))
    End Function

    Public Sub Change()
        Dim ao() As Object

        Debug.WriteLine("")
        Debug.WriteLine("---------------------------------------------------")
        Debug.WriteLine("")
        If MemberSearch("sov_reflXn", ao) Then Debug.WriteLine(ao(0).Name)
        If MemberSearch("sov_reflXn.mod1", ao) Then Debug.WriteLine(ao(1).Name)
        If MemberSearch("sov_reflXn.mod1.useDialog", ao) Then Debug.WriteLine(ao(2).Name & " = " & ao(2).GetValue(ao(1)))
        If MemberSearch("sov_reflXn.mod1.PathRoot", ao) Then Debug.WriteLine(ao(2).Name & " = " & ao(2).GetValue(ao(1)))
        If MemberSearch("sov_reflXn.fWin.BoolValue", ao) Then Debug.WriteLine(ao(2).Name & " = " & ao(2).GetValue(ao(1)))
        If MemberSearch("sov_reflXn.fWin.FileRoot", ao) Then Debug.WriteLine(ao(2).Name & " = " & ao(2).GetValue(ao(1)))
        If MemberSearch("sov_reflXn.mod1.MainForm.FileRoot", ao) Then Debug.WriteLine(ao(3).Name & " = " & ao(3).GetValue(ao(2)))
    End Sub
End Module

The error "Additional information: Field 'BoolValue' defined on type 'sov_reflXn.fWin' is not a field on the target object which is of type 'System.RuntimeType'." occurs on the line starting with the following text: if MemberSearch( "sov_reflXn.fWin.BoolValue", ... The main problem is how to 'solve' fWin. I beg Your pardon for the delay of my previous post, and I thank You all in advance.





Aucun commentaire:

Enregistrer un commentaire