无法反映私人方法

时间:2012-01-05 16:43:09

标签: vb.net reflection

所以我创建了这个帖子: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()子是私有的。如果你运行它,它将找不到此方法。如果我将其更改为受保护,但它可以正常工作。

我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

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

即使使用BindingFlags.NonPublic,您也不会在子类中看到私有成员。

显然,该解决方案会有点脆弱,因为它取决于您是否会在BaseType中看到该方法的子类级数。您可能需要循环使用类链,直到达到BaseTransactionalSaveManager的BaseType,然后找到该方法。

希望有所帮助。

答案 1 :(得分:1)

这实际上没有回答你的问题,但希望能给你一些灵感来使用模板方法模式。

首先,您通过让方法创建这些方法名称的列表来违反DRY。现在,如果您重命名方法,则必须在2个位置进行更改。

通过使用模板方法模式,您可以提供一种抽象方法,其中子类以正确的顺序定义所需的所有方法(替换它们现在提供的列表)。您将失去反映这些方法的所有开销,并且开发人员不再局限于没有方法参数。

此外,如果有一种很好的方法可以在没有反射的情况下执行,那么它通常是一种更清晰,更易于理解的解决方案。

- CW,因为它确实是一个很长的评论,并没有回答手头的问题。