通过反射传递派生 class 作为参数调用成员
Invoke member through reflection passing derived class as argument
我正在尝试调用 class 'CMyClass' 的方法 'MyMethod'。此方法有一个 "CBaseClass" 类型的参数,我正在传递一个 "CDerivedClass".
类型的对象
Class CBaseClass
Public m_AMember As String
Sub MethodOne()
// DoSomething
End Sub
End Class
Class CDerivedClass
Inherits CBaseClass
Public m_MyMember As Integer
Sub MethodTwo()
// DoSomething
End Sub
End Class
Class CMyClass
Sub MyMethod(ByVal obj As CBaseClass)
// DoSomething
End Sub
End Class
Sub Main()
'load assembly
Dim objAssembly As Assembly = Assembly.LoadFrom("myfile.dll")
'create class instance and MethodInfo object
Dim t As Type = objAssembly.GetType("MyNamespace.CMyClass")
Dim obj As Object = Activator.CreateInstance(t)
Debug.Assert(obj IsNot Nothing)
Dim m As MethodInfo = t.GetMethod("MyMethod")
Debug.Assert(m IsNot Nothing)
'Init arguments (only one)
Dim par As New CDerivedClass()
Dim parameters As Object() = New Object(0) {par}
'invoke method
m.Invoke(obj, parameters) '<<<< ArgumentException here!
End Sub
参数异常显示“'MyNamespace.CDerivedClass' 类型的对象无法转换为 'MyNamespace.CBaseClass' 类型。
我在 MyMethod 签名中将 "ByRef" 更改为 "ByVal",但没有任何变化。
我试图通过以下方式更改 'par' 对象的类型:
Dim par As CBaseClass = New CDerivedClass()
没有成功。
如何使用派生 class 的实例正确调用方法 "MyMethod"?
非常感谢。
我刚刚在独立项目中尝试了您的代码,它运行良好。我只调整了装配线以获取当前程序集而不是从文件中获取,并且我更改了 GetType 中的名称以反映我的命名空间。我的猜测是,您正在加载的 DLL 可能已过时,或者您在调用程序集中有重复的 类 定义,这就是它无法进行类型转换的原因。
Imports System.Reflection
Module Module1
Sub Main()
'load assembly
Dim objAssembly As Assembly = Assembly.GetExecutingAssembly()
'create class instance and MethodInfo object
Dim t As Type = objAssembly.GetType("ConsoleApplication1.CMyClass")
Dim obj As Object = Activator.CreateInstance(t)
Debug.Assert(obj IsNot Nothing)
Dim m As MethodInfo = t.GetMethod("MyMethod")
Debug.Assert(m IsNot Nothing)
'Init arguments (only one)
Dim par As New CDerivedClass()
Dim parameters As Object() = New Object(0) {par}
'invoke method
m.Invoke(obj, parameters) '<<<< No ArgumentException here!
End Sub
End Module
Class CBaseClass
Public m_AMember As String
Sub MethodOne()
End Sub
End Class
Class CDerivedClass
Inherits CBaseClass
Public m_MyMember As Integer
Sub MethodTwo()
End Sub
End Class
Class CMyClass
Sub MyMethod(ByVal obj As CBaseClass)
End Sub
End Class
最后我用序列化解决了...
所以'par'是包含调用项目中类型为CDerivedClass的序列化对象的字符串。
MyMethod 更改为:
MyMethod(xml_CBaseClass As String)
在 dll 项目中,字符串参数 xml_CBaseClass 被反序列化,创建 CBaseClass 对象。
注意:由于我有派生类型,派生的反序列化 class 给出了另一个问题。解决方案是
(我只是做了一点改动,序列化使用StringWriter,反序列化使用StringReader,而不是使用MemoryBuffer)。
CBaseClass 具有固定的派生类型,所以我将它们写成硬编码,但为了灵活起见,您可以这样做:
Dim subTypes as New List(Of Type) '<- all classes derived from 'myType'
For Each t In myType.Assembly.GetTypes()
If t.IsSubclassOf(myType) Then
subTypes.Add(t)
End If
Next
CBaseClass 及其所有派生类 classes 必须具有不带参数的构造函数 New()。
我使用 LoadFrom() 加载程序集,因为我不知道它们的名称(我使用 Dir() 从已知的固定文件夹中获取所有程序集)。
我正在尝试调用 class 'CMyClass' 的方法 'MyMethod'。此方法有一个 "CBaseClass" 类型的参数,我正在传递一个 "CDerivedClass".
类型的对象Class CBaseClass
Public m_AMember As String
Sub MethodOne()
// DoSomething
End Sub
End Class
Class CDerivedClass
Inherits CBaseClass
Public m_MyMember As Integer
Sub MethodTwo()
// DoSomething
End Sub
End Class
Class CMyClass
Sub MyMethod(ByVal obj As CBaseClass)
// DoSomething
End Sub
End Class
Sub Main()
'load assembly
Dim objAssembly As Assembly = Assembly.LoadFrom("myfile.dll")
'create class instance and MethodInfo object
Dim t As Type = objAssembly.GetType("MyNamespace.CMyClass")
Dim obj As Object = Activator.CreateInstance(t)
Debug.Assert(obj IsNot Nothing)
Dim m As MethodInfo = t.GetMethod("MyMethod")
Debug.Assert(m IsNot Nothing)
'Init arguments (only one)
Dim par As New CDerivedClass()
Dim parameters As Object() = New Object(0) {par}
'invoke method
m.Invoke(obj, parameters) '<<<< ArgumentException here!
End Sub
参数异常显示“'MyNamespace.CDerivedClass' 类型的对象无法转换为 'MyNamespace.CBaseClass' 类型。
我在 MyMethod 签名中将 "ByRef" 更改为 "ByVal",但没有任何变化。 我试图通过以下方式更改 'par' 对象的类型:
Dim par As CBaseClass = New CDerivedClass()
没有成功。 如何使用派生 class 的实例正确调用方法 "MyMethod"? 非常感谢。
我刚刚在独立项目中尝试了您的代码,它运行良好。我只调整了装配线以获取当前程序集而不是从文件中获取,并且我更改了 GetType 中的名称以反映我的命名空间。我的猜测是,您正在加载的 DLL 可能已过时,或者您在调用程序集中有重复的 类 定义,这就是它无法进行类型转换的原因。
Imports System.Reflection
Module Module1
Sub Main()
'load assembly
Dim objAssembly As Assembly = Assembly.GetExecutingAssembly()
'create class instance and MethodInfo object
Dim t As Type = objAssembly.GetType("ConsoleApplication1.CMyClass")
Dim obj As Object = Activator.CreateInstance(t)
Debug.Assert(obj IsNot Nothing)
Dim m As MethodInfo = t.GetMethod("MyMethod")
Debug.Assert(m IsNot Nothing)
'Init arguments (only one)
Dim par As New CDerivedClass()
Dim parameters As Object() = New Object(0) {par}
'invoke method
m.Invoke(obj, parameters) '<<<< No ArgumentException here!
End Sub
End Module
Class CBaseClass
Public m_AMember As String
Sub MethodOne()
End Sub
End Class
Class CDerivedClass
Inherits CBaseClass
Public m_MyMember As Integer
Sub MethodTwo()
End Sub
End Class
Class CMyClass
Sub MyMethod(ByVal obj As CBaseClass)
End Sub
End Class
最后我用序列化解决了...
所以'par'是包含调用项目中类型为CDerivedClass的序列化对象的字符串。
MyMethod 更改为:
MyMethod(xml_CBaseClass As String)
在 dll 项目中,字符串参数 xml_CBaseClass 被反序列化,创建 CBaseClass 对象。
注意:由于我有派生类型,派生的反序列化 class 给出了另一个问题。解决方案是 (我只是做了一点改动,序列化使用StringWriter,反序列化使用StringReader,而不是使用MemoryBuffer)。
CBaseClass 具有固定的派生类型,所以我将它们写成硬编码,但为了灵活起见,您可以这样做:
Dim subTypes as New List(Of Type) '<- all classes derived from 'myType'
For Each t In myType.Assembly.GetTypes()
If t.IsSubclassOf(myType) Then
subTypes.Add(t)
End If
Next
CBaseClass 及其所有派生类 classes 必须具有不带参数的构造函数 New()。
我使用 LoadFrom() 加载程序集,因为我不知道它们的名称(我使用 Dir() 从已知的固定文件夹中获取所有程序集)。