2012-01-05 37 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