问题
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