2012-08-07 24 views
-2

下面是測試代碼:如何實現與目標函數的參數的枚舉類型反射

Public Class Class2 
    Public GoodName as String 
    Public Function someFunction() 
    End Function 
End Class 

Public Class Class1 
    Public Enum ENUM_VAL1_ 
     abc = 1 
     def = 2 
    End Enum 

    Public Enum ERROR_VAL1_ 
     yhn = 1 
     ujm = 2 
    End Enum 

    Public Function fun1(byval _enumArg1 as ENUM_VAL1_, 
         byval _stringArg as String, 
         byref _classArg Class2) as ERROR_VAL1_ 
     ... SOMETHING HERE 
     return something 
    End Function 
End Class 

和測試

Dim asm As Assembly = Assembly.LoadFrom(<the source>) 
    If asm Is Nothing Then Return Nothing 

    Dim typ As Type = asm.GetType(<namespace>.<class1>) 
    If typ Is Nothing Then Return Nothing 

    Dim obj As Object = Activator.CreateInstance(typ) 
    If obj Is Nothing Then Return Nothing 

    Dim arg As Object() = New Object() {ENUM_VAL1_.abc, "qazxsw", New Class2} 

    Dim res As Object = typ.InvokeMember(_ 
     "fun1", _ 
     BindingFlags.[Default] Or BindingFlags.InvokeMethod, _ 
     Nothing, _ 
     obj, _ 
     arg) 

的〔Dim res As Object = typ.InvokeMember(_ "fun1", _ BindingFlags.[Default] Or BindingFlags.InvokeMethod, _ Nothing, _ obj, _ arg)] 返回一個錯誤:function '[fullname]' not found.

然後我意識到fun1簽名與我的調用不同(即使枚舉值是整數)。我做了一些研究,並在目標程序集的屬性或函數的參數與標準類型不同時找到了有關如何實現反射的「一些」示例。但我成功地將這些樣本「概念」翻譯成我的需要。

所以,在這裏我放了一些虛擬類與虛擬枚舉類型來指出問題的骨架。

原始代碼是關於Windows防火牆/端口(win7/xp/vista),其中有許多枚舉值,包括來自firewallApi.dll和Hnetcfg.dll的類型。

我的問題是,我不能「InvokeMember」(也稱爲「setProperties方法」和「setProperties方法」)用說:

Dim args As Object() = New Object() {"SQL", 6, "1433", 1} 

從哪裏組裝我的功能有以下參數類型。

Public Function PortExists(_ 
    ByVal _ruleName As String, _ 
    ByVal _protocol As NET_FW_IP_PROTOCOL_, _ 
    ByVal _remotePorts As String, _ 
    ByVal _direction As NET_FW_RULE_DIRECTION_ _ 
) As FW_ERROR_CODE 

確定,以簡化我在我自己的枚舉類型(需要被安裝任何附加的庫)

Public Function PortExists(_ 
    ByVal _ruleName As String, _ 
    ByVal _protocol As FW_IP_PROTOCOL, _ 
    ByVal _remotePorts As String, _ 
    ByVal _direction As FW_RULE_DIRECTION _ 
) As FW_ERROR_CODE 

不知何故參數「6」和「1」應該被轉換到FW_IP_PROTOCOLFW_RULE_DIRECTION類型分別...

我不知道如何!

+0

請解釋你正在努力達到什麼以及爲什麼它不工作。怎麼了?問題是什麼? – 2012-08-07 16:53:56

回答

0

通常一個好的設計會讓Reflection變得多餘。我的建議是讓不同的對象實現一些定義要調用的函數的通用接口。

通用定義:

Public Enum MyValueEnum 
    value1 = 1 
    value2 = 2 
End Enum 

Public Enum MyErrorEnum 
    error1 = 1 
    error2 = 2 
End Enum 

Public Class SomeClass 
    Public GoodName As String 

    Public Function SomeFunction() As Object 
     Return Nothing 
    End Function 
End Class 

接口

Public Interface IMyInterface 
    Function TheFunction(ByVal val As MyValueEnum, ByVal name As String, _ 
         ByRef someObject As SomeClass) As MyErrorEnum 
End Interface 

兩個不同的類實現接口

Public Class SomeImplementation 
    Implements IMyInterface 

    Public Function TheFunction(ByVal val As MyValueEnum, ByVal name As String, _ 
           ByRef someObject As SomeClass) As MyErrorEnum _ 
     Implements IMyInterface.TheFunction 
     '... 
     Return MyErrorEnum.error1 
    End Function 
End Class 

Public Class SomeOtherImplementation 
    Implements IMyInterface 

    Public Function TheFunction(ByVal val As MyValueEnum, ByVal name As String, _ 
           ByRef someObject As SomeClass) As MyErrorEnum _ 
     Implements IMyInterface.TheFunction 
     '... 
     Return MyErrorEnum.error2 
    End Function 
End Class 

測試

Dim obj As IMyInterface 
Dim result As MyErrorEnum 

obj = New SomeImplementation() 
result = obj.TheFunction(MyValueEnum.value1, "test", New SomeClass()) 

obj = New SomeOtherImplementation() 
result = obj.TheFunction(MyValueEnum.value2, "another test", New SomeClass()) 
+0

該<<昏暗RES作爲對象= typ.InvokeMember(_ 「FUN1」,_ 的BindingFlags [默認]或者BindingFlags.InvokeMethod,_ 沒什麼,_ OBJ,_ ARG。)>> 返回一個錯誤:找不到功能''。 然後我意識到fun1簽名不同於我的反射(即使枚舉值是整數)。我做了一些研究,並在目標程序集的屬性或函數的參數與標準類型不同時找到了有關如何實現反射的「一些」示例。但我成功地將這些樣本「概念」翻譯成我的需要。 – Saar 2012-08-07 18:58:44

+0

我想我用「實施」表達誤導你。我的問題是反射,其中目標函數/屬性具有枚舉或對象類型的參數。對不起...... – Saar 2012-08-07 19:08:57

+0

枚舉實際上只是整數,所以在使用反射時,應該只是傳遞整數而已。 – 2012-08-07 20:06:52

0

好的,這裏是解決方案。

當我們從反射中使用Invoke方法時,我們必須將參數作爲對象(object())與類型的完全匹配進行傳遞。 即使枚舉類型的值是一個整數(這是我的原始問題),我不得不將這個值轉換爲引用程序集類型的確切枚舉類型。所以下面的函數< _FEnumToObject>將完成這項工作。我添加_F來將我所有的私有函數推入列表底部並對它們進行分組(IDE屬性列表); _S將站在潛艇和_P爲屬性...

Private Function _FEnumToObject(_ 
    ByVal _typeName As String, _ 
    ByVal _typeValue As String _ 
) As Object 
    Dim enumType As Type = m_Assembly.[GetType](_typeName) 
    Dim enumInfo As FieldInfo = enumType.GetField(_typeValue) 
    Dim valueINT As Integer = CInt(enumInfo.GetValue(enumType)) 
    Dim valueOBJ As Object = [Enum].ToObject(enumType, valueINT) 
    Return valueOBJ 
End Function 

該下一功能< _FProtocolToObject>是協議值(enumurated)轉換爲一個對象。

Public Function _FProtocolToObject(ByVal _protocol As FW_IP_PROTOCOL) As Object 
    'where <m_AssemblyRef> is like "wf7." 
    Return _FEnumToObject(m_AssemblyRef + "FW_IP_PROTOCOL", _protocol.ToString) 
End Function 

這裏是最後的呼叫:

Public Function PortExists(_ 
    ByVal _ruleName As String, _ 
    ByVal _protocol As FW_IP_PROTOCOL, _ 
    ByVal _portNumber As Integer _ 
) As Boolean 
    If m_AssemblyNotFound Then Return False 
    Static mi As MethodInfo = m_RemoteType.GetMethod("PortExists") 
    Dim m As FW_ERROR_CODE = FW_ERROR_CODE.UNKNOWN 
    Try 
     Dim a As Object = New Object() _ 
      { _ 
       _ruleName, _ 
       _FProtocolToObject(_protocol), _ 
       _portNumber _ 
      } 
     m = mi.Invoke(m_RemoteObject, a) 

    Catch ex As Exception 
     'some error handler here... 

    End Try 
    Return (m = FW_ERROR_CODE.SUCCESS) 
End Function 

我也張貼一些額外的代碼在我的示例代碼介紹一些不明原因的警戒/解除警戒變量賦值。

Private ReadOnly Property _PAssemblyPath() As String 
    Get 
     Dim ad As String = IO.Path.Combine(My.Application.Info.DirectoryPath, "bin") 
     Dim af As String = IO.Path.Combine(ad, _PAssemblyName + ".dll") 
     Return af 
    End Get 
End Property 

的Public Sub New()

m_AssemblyPath = _PAssemblyPath 
    m_AssemblyRef = _PAssemblyName + "." 
    m_ClassPath = m_AssemblyRef + _PClassName 

    If IO.File.Exists(m_AssemblyPath) Then 

     Dim name As New AssemblyName() 
     name.CodeBase = m_AssemblyPath 
     m_Assembly = AppDomain.CurrentDomain.Load(name) 
     m_RemoteObject = m_Assembly.CreateInstance(m_ClassPath) 
     m_RemoteType = m_Assembly.[GetType](m_ClassPath) 
     m_AssemblyNotFound = False 

    Else 
     'some error handler here 

    End If 

End Sub 

只是假設 'SCSysInfo' 是一個實用工具類,檢查OS系統等等

Private ReadOnly Property _PClassName() As String 
    Get 
     Dim s As String = "CFwRule" 
     If SCSysInfo.IsWin7 Then 
      s += "7" 
     ElseIf SCSysInfo.IsWinVista Then 
      s += "Vista" 
     ElseIf SCSysInfo.IsWinXP Then 
      s += "XP" 
     End If 
     Return s 
    End Get 
End Property 
Private ReadOnly Property _PAssemblyName() As String 
    Get 
     Dim s As String = String.Empty 
     If SCSysInfo.IsWin7 Then 
      s = "fw7" 
     ElseIf SCSysInfo.IsWinVista Then 
      s = "fwv" 
     ElseIf SCSysInfo.IsWinXP Then 
      s = "fwxp" 
     End If 
     Return s 
    End Get 
End Property 

'PortExists' 功能在我的班級(部分上面列出)中有兩個vista和win7的簽名。我必須提到的一點是反射不能識別方法/屬性的多重簽名。使用反射時,您必須只有一個方法或屬性的簽名。談到我的情況:win7,vista和xp爲端口提供了完全不同的屬性來編程。在每個程序集(我在各自的環境中編譯)中,都有「相同」的方法和屬性,它們具有不同數量的參數。從我的「適配器」類(上面公佈的部分)中,我從3個不同簽名(基於OS選擇適當簽名)的所有3個程序集中調用「相同」方法。所以,「PortExists」方法的所有3個簽名都在我的「適配器」類中。我希望我的解釋有道理......謝謝,