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

与世无争的帅哥 提交于 2019-12-25 06:04:20

问题


I have multiple and different methods that I can't edit:

    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

I started creating a class like this:

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

The problem is:

How can I pass a Method that has some arguments and recall them in ExecuteFunction? I tried using Action but it does not fit with its definition and usage.


For example, I would like to do something like this:

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

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

Is it possible? How can I get this effect / which pattern should I use?


回答1:


How can I pass a Method that has some arguments

The problem is the code which creates and uses MyClassWrapper isnt passing in any arguments, and since Action has no return, it is not the right choice if you need the return.

The example shows creating a new object wrapper for each method, which seems inefficient. For simplicity, I changed the arguments to basic types for the class you dont have access to:

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

The different names seems to indicate the target methods are not overloads, but MyWrapperClass seems to wants to interact with them as if they are by using the same name ExecuteFunction. Even though the question code is contrived for posting here, the CantEditClass is exposing 3 different methods. I am not sure it adds clarity to have to discern which method is being called by the order/type of arguments.

Basic Answer

Literally pass the address of the function to the Wrapper method. For this, the wrapper methods could be declared using Func() to define the method chained to:

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

Usage:

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

Declare a Delegate for Reuse

' 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)  

The fDel delegate can be set once if declared at some class/form level. If objSealed is recreated, the code will need to reset the delegate. Especially with a generic name or quasi overload the named Delegate can help you keep track of which is which.

Both are rather cumbersome because the burden is put on the consuming code.

Delegate as a Wrapper Type

You could also have the wrapper "hold onto" the delegate. In 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    

Usage:

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

Slightly less cumbersome. You could also let the wrapper set all these up and hold onto them by passing the sealed class object in the constructor:

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

Smart Wrapper, No Delegates

Delegates may make sense if there is variation in which of these is invoked in conjunction with a Wrapper method. If not, the Wrapper could be a little smarter:

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

The code can invoke either version easily:

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)   


来源:https://stackoverflow.com/questions/33570208/how-to-pass-a-method-with-multiple-parameters-as-argument-of-another-method

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!