通过反射访问变量

时间:2017-06-19 13:28:20

标签: .net vb.net variables reflection reference

我有一个用VB.NET编写的Windows窗体解决方案。使用模块MOD1的反射我想要模块MOD2的get / set公共变量。一个强大的约束是只使用字符串,就像命令行解释器一样。下面是我用来重建失败环境的代码。

在访问简单变量(useDialog)时,此代码的行为与预期一致,但在访问复杂变量(fWin或MainForm)时会出现一些问题。我犯了一些错误,但我没有意识到哪一个!

请注意:fWin是Windows窗体类。

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
                        dim Container as object = nothing
                        try
                            Container = 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
                        if ( currType is nothing ) then
                            try
                                Container = Container.GetValue( nothing )
                                LoP.Add( Container.GetType().GetField( mcName( imc_scan+1 ) ) )
                            catch ex1 as Exception
                                MessageBox.Show( ex1.Message )
                            end try
                        end if
                    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

在'sov_reflXn.fWin'类型上定义的错误“附加信息:字段'BoolValue'不是目标对象上的字段'System.RuntimeType'。”发生在以下文字开头的行上:如果是MemberSearch(“sov_reflXn.fWin.BoolValue”,......主要问题是如何'解决'fWin。 请原谅我上一篇文章的延迟,我提前感谢你们。

1 个答案:

答案 0 :(得分:0)

问题是FieldInfo.GetValue需要一个对象实例来获取字段的值,但是你传递的是System.Type:你传递了sov_reflXn.fWin的类型信息{1}}而不是它的实例。

由于你有类型,你可以通过反射得到一个构造函数,但这可能不是你真正想做的。您需要找到一种方法来获取您想要操作代码的实例。

如果您有模块中的实例,则可以在此处使用答案:How do I set a field value in a VB.NET module using Reflection?GetValue替换为SetValue,并将Nothing作为实例传递,例如

Call MemberSearch("sov_reflXn.mod1.MainForm.FileRoot", ao)
Debug.WriteLine(ao(1).GetField("PathRoot").GetValue(Nothing))