我有一个用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。 请原谅我上一篇文章的延迟,我提前感谢你们。
答案 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))