所以我创建了这个帖子: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 :(得分:2)
而不是Me.GetType.InvokeMember
(ProcessStage的第一行),您需要调用Me.GetType.BaseType.InvokeMember
即使使用BindingFlags.NonPublic
,您也不会在子类中看到私有成员。
显然,该解决方案会有点脆弱,因为它取决于您是否会在BaseType中看到该方法的子类级数。您可能需要循环使用类链,直到达到BaseTransactionalSaveManager
的BaseType,然后找到该方法。
希望有所帮助。
答案 1 :(得分:1)
这实际上没有回答你的问题,但希望能给你一些灵感来使用模板方法模式。
首先,您通过让方法和创建这些方法名称的列表来违反DRY。现在,如果您重命名方法,则必须在2个位置进行更改。
通过使用模板方法模式,您可以提供一种抽象方法,其中子类以正确的顺序定义所需的所有方法(替换它们现在提供的列表)。您将失去反映这些方法的所有开销,并且开发人员不再局限于没有方法参数。
此外,如果有一种很好的方法可以在没有反射的情况下执行,那么它通常是一种更清晰,更易于理解的解决方案。
- CW,因为它确实是一个很长的评论,并没有回答手头的问题。