2012-08-07 2 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 서명이 내 호출과 다릅니다 (enum 값이 정수 임에도 불구하고). 나는 약간의 연구를 수행했고 대상 어셈블리의 속성이나 함수가 표준 형식과 다른 인수를 가질 때 반사를 구현하는 방법에 대한 "일부"샘플을 발견했습니다. 그러나 나는 그 견본 "개념"을 나의 필요로 번역하는데 성공했다.

여기에서, 문제의 골격을 지적하기 위해 더미 열거 형을 가진 더미 클래스를 몇 개 넣었습니다.

원본 코드는 firewallApi.dll 및 Hnetcfg.dll의 유형을 포함하여 많은 열거 값이있는 Windows 방화벽/포트 (win7/xp/vista)입니다.

내가 가진 문제는 내가 할 수없는 "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

성취하려는 것을 설명하고 그것이 효과가없는 이유를 설명하십시오. 무슨 일이야? 문제가 무엇입니까? 개체로서는 = typ.InvokeMember –

답변

0

흔히 좋은 디자인은 반사를 불필요하게 만듭니다. 필자의 제안은 다른 객체가 호출 할 함수를 정의하는 공통 인터페이스를 구현하도록하는 것이다.

일반적인 정의 :

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 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 

테스트를 구현

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

두 개의 서로 다른 클래스

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 (_ "fun1"_ BindingFlags의 [초기] 또는 BindingFlags.InvokeMethod, _ 아무것도 _ OBJ, _ 인수 .) >> 오류를 반환 : 함수 ''을 찾을 수 없습니다. 그런 다음 fun1 서명이 내 리플렉션과 다르다는 사실을 알고 있습니다 (열거 형 값은 정수 임에도 불구하고). 나는 약간의 연구를 수행했고 대상 어셈블리의 속성이나 함수가 표준 형식과 다른 인수를 가질 때 반사를 구현하는 방법에 대한 "일부"샘플을 발견했습니다. 그러나 나는 그 견본 "개념"을 나의 필요로 번역하는데 성공했다. – Saar

+0

나는 "구현"표현으로 당신을 오해한다고 생각합니다. 내 문제는 반영, 대상 함수/속성을 열거 형 또는 개체 형식의 인수가 있습니다. 죄송합니다 ... – Saar

+0

열거 형은 실제로는 정수형이므로 반사식을 사용할 때 정수 대신 전달하는 것이 좋습니다. –

0

자, 해결책이 있습니다.

리플렉션에서 Invoke 메서드를 사용할 때는 형식이 정확히 일치하는 개체 (object())로 인수를 전달해야합니다. enum 유형의 값이 정수 (원래 문제가있는 곳)이지만이 값을 참조 어셈블리 유형의 정확한 enum 유형으로 변환해야했습니다. 따라서 다음 함수 < _FEnumToObject>가이 작업을 수행합니다._F를 추가하여 목록의 모든 개인 함수를 맨 아래로 밀어 그룹화했습니다 (IDE 속성 목록). _S는

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 

... 서브 및 속성이 다음 _P위한 기능 < _FProtocolToObject> 객체에 (enumurated) 프로토콜 값을 변환하는 것이다 스탠드 것이다.

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 

내 샘플 코드의 일부 설명 할 수없는/해제 변수 할당을 제시하는 것이 몇 가지 추가 코드를 게시하도록하겠습니다 : 여기

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 

그리고

마지막 호출입니다.

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 

공공 서브 뉴()

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 가지 서명은 모두 "어댑터"클래스에 있습니다. 제 설명이 의미가 있기를 바랍니다 ... 감사합니다,