2012-01-05 81 views
0

所以我創建此線程:Invoking Private/Protected Methods Via Reflection From The Same Object Instance (or Base)不能反映私人方法

而我們得到了問題修復保存私人方法。因爲這可能不是同一個問題,所以我認爲最好在完整源代碼中發佈不同的問題。這仍然是一項正在進行的工作,但它是功能性的。

的基類:

Public MustInherit Class BaseTransactionalSaveManager : Implements ITransactionalSaveManager 

    '---- Public Properties & Backing Fields ----' 

    Public Property FormDataIsValid As Boolean Implements ITransactionalSaveManager.FormDataIsValid 

    '---- Private Properties & Backing Fields ----' 

    Protected Property Stages As Collections.Generic.List(Of String) 
    Protected Property StageCausedRollback As Containers.GenericNamedValuePair(Of String, Boolean) 
    Protected Property CurrentStage As Integer 

    '---- Event Declarations & Associated Methods ----' 

    Public Event TransactionCancelled As EventHandler(Of CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.TransactionCancelled 

    Public Event TransactionCompleted As EventHandler(Of CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.TransactionCompleted 

    Public Event TransactionStagePassed As EventHandler(Of CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.TransactionStagePassed 

    Protected Overridable Sub OnTransactionCancelled(e As CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.OnTransactionCancelled 

     RaiseEvent TransactionCancelled(Me, e) 

    End Sub 

    Protected Overridable Sub OnTransactionCompleted(e As CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.OnTransactionCompleted 

     RaiseEvent TransactionCompleted(Me, e) 

    End Sub 

    Protected Overridable Sub OnTransactionStagePassed(e As CustomEventArgs.GenericSingleEventArgs(Of String)) Implements ITransactionalSaveManager.OnTransactionStagePassed 

     RaiseEvent TransactionStagePassed(Me, e) 

    End Sub 

    '---- Constructors ----' 

    Public Sub New() 

     Stages = New Collections.Generic.List(Of String) 
     SetStages() 
     CurrentStage = 0 

     StageCausedRollback = New Containers.GenericNamedValuePair(Of String, Boolean) 
     FormDataIsValid = True 

    End Sub 

    '---- Public Methods ----' 

    Public Sub ProcessStage() Implements ITransactionalSaveManager.ProcessStage 

     ' Use stage to fire the correct method. 

     Me.GetType.InvokeMember(Stages(CurrentStage), 
           Reflection.BindingFlags.InvokeMethod Or 
           Reflection.BindingFlags.NonPublic Or 
           Reflection.BindingFlags.Public Or 
           Reflection.BindingFlags.Instance, 
           Type.DefaultBinder, Me, Nothing) 

     ' Determine if the stage should cause a rollback. 

     If Not StageCausedRollback.Value Then 

      RollBackTransaction(StageCausedRollback.Name) 
      Exit Sub 

     End If 

     ' Check if this stage is the last one. 

     If Stages(CurrentStage) = Stages.Last Then 

      OnTransactionCompleted(New CustomEventArgs.GenericSingleEventArgs(Of String)(Stages(CurrentStage))) 

     Else 

      OnTransactionStagePassed(New CustomEventArgs.GenericSingleEventArgs(Of String)(Stages(CurrentStage))) 

     End If 

    End Sub 

    Public Overridable Function TryCancelTransaction() As Boolean Implements ITransactionalSaveManager.TryCancelTransaction 

     OnTransactionCancelled(New CustomEventArgs.GenericSingleEventArgs(Of String)("")) 
     Return True 

    End Function 

    '--- Protected & Overridable Methods ----' 

    Protected Overridable Sub SetStages() 

     Me.Stages.Add(MethodNameToString(AddressOf Me.ConfirmFormDataIsValid)) 

    End Sub 

    Protected Overridable Sub RollBackTransaction(stageThatCauseRollback As String) 

     OnTransactionCancelled(New CustomEventArgs.GenericSingleEventArgs(Of String)(stageThatCauseRollback)) 

    End Sub 

    Protected Function MethodNameToString(addressOfMethod As Action) As String 

     Return addressOfMethod.Method.Name 

    End Function 

    Private Sub ConfirmFormDataIsValid() 

     StageCausedRollback.Name = MethodNameToString(AddressOf ConfirmFormDataIsValid) 
     StageCausedRollback.Value = If(FormDataIsValid, True, False) 

    End Sub 

End Class 

所以這個類是由一個(到目前爲止)空的子類繼承和ProcessStage被調用。注意ConfirmFormDataIsValid()子是私有的。如果你運行它,它不會找到這個方法。如果我將其更改爲受保護,但它工作正常。

我錯過了什麼嗎?

+0

謝謝@vcsjones修復突出顯示...我做錯了什麼? – deanvmc 2012-01-05 16:46:47

+1

回覆:「心理看語法高亮」。語法highlighter使用標籤來決定代碼的編寫語言。由於您擁有C#標籤,它選擇了通過VB.NET突出顯示的C#。您還可以明確地說出該代碼與[HTML評論]的語言(http://meta.stackexchange.com/questions/78363/manually-specify-language-for-syntax-highlighting)。 – vcsjones 2012-01-05 16:46:47

+0

您是否考慮過[Template Method Pattern](http://en.wikipedia.org/wiki/Template_method_pattern)而不是反射?我敢打賭它會更穩定。 (這個評論是基於這個_and_鏈接的問題。) – 2012-01-05 16:47:13

回答

2

而不是Me.GetType.InvokeMember(ProcessStage的第一行),你需要調用Me.GetType.BaseType.InvokeMember

你不會看到私有成員在子類中,即使BindingFlags.NonPublic

很明顯,解決方案會有點脆弱,因爲它取決於你有多少級別的子類,你是否會在BaseType中看到方法。您可能需要循環訪問類的鏈,直到達到基本類型BaseTransactionalSaveManager,然後找到該方法。

希望有所幫助。

+0

就這樣我們在同一頁上,上面列出的代碼是基類,這仍然適用? – deanvmc 2012-01-05 17:25:01

+0

是的,因爲「Me」是指由調用者創建的類型,而不是代碼實際所在的基類。如果您調用Me.GetType()。從基類內部的方法命名,您會看到它始終是基類的名稱。當然,如果你真的創建了一個基類類型的實例,但你已經創建了MustInherit,那就不一樣了,所以這是不可能的。 – Richard 2012-01-05 17:28:04

+0

啊是的..當再次閱讀時,我拿起了。嗯....我可能不得不重新設計......無論哪種方式,這正確地解決了這個問題,並提供了原因..爲你的綠色勾號我的朋友! – deanvmc 2012-01-05 17:30:33

1

這真的不能回答你的問題,但希望給你一些靈感來使用模板方法模式。

首先,您違反DRY方法創建這些方法名稱的列表。現在,如果您進行方法重命名,則必須在兩個地方進行更改。

通過使用模板方法模式,您可以提供一個抽象方法,其中子類定義所有要調用的方法,並按正確的順序(替換它們現在提供的列表)。您將失去反映到這些方法的所有開銷,並且開發人員不再受限於任何方法參數。

另外,如果有一種很好的方式可以做而不需要反思,它通常是一個更清晰和易於理解的解決方案。

- CW,因爲它確實是一個非常長的評論,並沒有回答手頭的問題。

+0

+1我完全同意。我不是這種方式的粉絲,我只是有一個MustInherit上的進程,並讓每個派生實例照顧自己的流量......這是爲了隱藏複雜性,但基於與我的經理對話,我可能還沒有使用你的建議。 (PS重構 - >重命名意味着我只需要更改一次:)) – deanvmc 2012-01-05 17:34:54