Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
165 views
in Technique[技术] by (71.8m points)

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

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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)   

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...