如何将具有多个参数的方法作为另一个方法的参数传递

How to pass a method with multiple parameters as argument of another method

我有多种不同的方法无法编辑:

    Public Function Test1(A As Integer, B As String, C As Boolean) As Boolean
    Public Function Test2(A As Boolean, B As Double) As DataTable
    Public Function Test3(A As String) As Integer

我开始像这样创建 class:

Public Class MyWrapperClass

    Dim _method As Action()

    Public Sub New(Method As Action())
        _method = Method
    End Sub

    Public ExecuteFunction()
        _method()
        ' And do something with the result
    End Function

End Class

问题是:

如何传递具有一些参数的 Method 并在 ExecuteFunction 中调用它们?我尝试使用 Action 但它不符合其定义和用法。


例如,我想做这样的事情:

Dim test1 = new MyWrapperClass(Test1)
test1.ExecuteFunction(1, "test1", true)

Dim test2 = new MyWrapperClass(Test2)
test2.ExecuteFunction(true, 0.34)

可能吗?我怎样才能得到这种效果/我应该使用哪种模式?

How can I pass a Method that has some arguments

问题是创建和使用 MyClassWrapper 的代码没有传入任何参数,并且由于 Action 没有 return,如果您需要return.

该示例显示为每个方法创建一个新的对象包装器,这似乎效率低下。为简单起见,我将参数更改为您无法访问的 class 的基本类型:

Public Function Test1(A As Integer, B As String, C As Boolean) As Int32
Public Function Test2(A As Boolean, B As Double) As String
Public Function Test3(A As String) As Integer

不同的名称似乎表明目标方法是不是重载,但MyWrapperClass似乎想与他们就好像他们使用相同的名字 ExecuteFunction。尽管问题代码是为了在此处发布而设计的,但 CantEditClass 公开了 3 种不同的方法。我不确定必须辨别参数 order/type 调用了哪个方法是否会增加清晰度。

基本答案

直接将函数的地址传递给Wrapper方法。为此,可以使用 Func() 声明包装器方法以定义链接到的方法:

Public Function Test1Exec(f As Func(Of Int32, String, Boolean, Int32), a As Int32) As Int32
    Dim n As Int32 = f(a, "foo", False)
End Function

用法:

Private wrapper As Wrapper
Private objSealed As CantEditClass
...
wrapper = New Wrapper
objSealed = New CantEditClass   
...
Dim b = wrapper.Test1Exec(AddressOf objSealed.Test1, 6)

声明一个委托以供重用

' declared with the other objects
Private fDel As Func(Of Int32, String, Boolean, Int32) 
...
' initialized:
fDel = AddressOf objSealed.Test1
...
Dim b = wrapper.Test1Exec(fDel, 6)  

如果在某个 class/form 级别声明,fDel 委托可以设置一次。如果重新创建 objSealed,代码将需要重置委托。特别是对于通用名称或准重载,命名委托可以帮助您跟踪哪个是哪个。

两者都比较麻烦,因为负担放在了消费代码上。

委托为包装类型

您还可以让包装器 "hold onto" 委托。在 Wrapper:

Public Delegate Function Test1Delegate(a As Int32, b As String, c As Boolean) As Int32
Public Function Test1aExec(f As Test1Delegate, a As Int32) As Int32
    Dim n As Int32 = f(a, "foo", False)
End Function    

用法:

Dim fDel2 As Wrapper.Test1Delegate = AddressOf objSealed.Test1
...
b = wrapper.Test1aExec(fDel2, 6)    

稍微不那么麻烦。您还可以让包装器设置所有这些并通过在构造函数中传递密封的 class 对象来保留它们:

Private Delegate Function Test2Delegate(a As Boolean, b As Double) As String
Private Test2D As Test2Delegate

Private Delegate Function Test3Delegate(a As String) As Integer
Private Test3D As Test3Delegate

Public Sub New(target As CantEditClass)
    ' internal assignment
    Test2D = AddressOf target.Test2
    Test3D = AddressOf target.Test3
End Sub

智能包装器,无委托

如果与 Wrapper 方法一起调用其中的委托存在差异,则委托可能有意义。如果不是,Wrapper 可能更聪明一点:

Public ReadOnly TargetObject As CantEditClass
' alternatively pass the object 
' if the calling code needs it for something like events
Public Sub New()
    ' internal mapping
    Dim TargetObject = New CantEditClass
End Sub

Public Function Text1Ex(arg1 As Int32, arg2 As String, arg3 As Boolean) As Int32
    Dim result = TargetObject.Test1(arg1, arg2, arg3)
    ' work with result
    Return If(arg3, arg1, -arg1)
End Function

代码可以轻松调用任一版本:

MyWrap = New Wrapper()

' call EXtended wrapper version
Dim result = MyWrap.Text1Ex(42, "ziggy", False)
' invoke the native version:
result = MyWrap.TargetObject.Test1(42, "zalgo", True)