Sunday, February 19, 2017

Passing Action as a parameter

This has nothing to do with WPF but while working on a problem that was best solved using an Action I began to wonder how you would pass an action around across thread, process, and machine boundaries.

Here is a console application that demonstrates the use of an action, passing it across a thread boundary, and then a process and machine boundary.

Start a console application in visual basic and call it "Actions". Then add a WCFService project and leave the name as WcfReferenceLibrary1. Here is the solution explorer.


The contents of Module1.vb are...

Imports System.Threading
Module Module1

    Sub Main()
        Console.WriteLine("Action on current thread")

        Dim a As Action(Of String)
        a = Sub(s) Console.WriteLine(s)
        a("It Worked!")
        Console.WriteLine("---------------------------")

        Console.WriteLine("Action on another thread")
        Dim t As New Thread(New ParameterizedThreadStart(AddressOf newThread))
        t.Start(a)
        ' Wait for the thread to terminate
        Do While (t.IsAlive)
            Thread.Sleep(10)
        Loop
        Console.WriteLine("---------------------------")

        Console.WriteLine("Action on another process")
        Console.WriteLine("Can't be done - process only takes string arguments")
        Console.WriteLine("---------------------------")

        ' You have to add the service reference before the following
        ' code will compile
        Try
            Console.WriteLine("Action on another machine")
            Dim sr As New ServiceReference1.Service1Client
            sr.Work(a)
            Console.WriteLine("---------------------------")
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try

        Console.WriteLine()
        Console.WriteLine("Press any key to exit")
        Console.ReadKey()
    End Sub

    Sub newThread(a As Action(Of String))
        a("Thread Worked!")
    End Sub
End Module

The IWCFService1,vb and WCFService1,vb are in their own project and look like this...
<ServiceContract()>
Public Interface IService1

    <OperationContract()>
    Sub Work(ByVal a As Action(Of String))


End Interface

Public Class Service1
    Implements IService1

    Public Sub Work(ByVal a As Action(Of String)) Implements IService1.Work
        a("Machine Worked!")
    End Sub

End Class

Build the Service1 project.

To add the Service1 reference to the Actions project you right click on the "Actions" project and select "Add" -> "Service Reference". Click on [Discover], expand "Design_Item_Addresses...", click on Service1 and click [OK].


When you run the solution you will see output like this...


There are four tests here - what do they tell us?
1. Using an action in the same thread it is defined works fine.
2. Using an action in a different thread but in the same process also works fine.
3. There is no way to pass an action to a process using command parameters because they must be strings.
4. WCF allows you to define and compile a method that takes an Action but actions cannot be serialized so the method call fails at run time.

No comments:

Post a Comment