Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Helper Class for Calling Asynchronous Methods using Func<T> Generics

0.00/5 (No votes)
1 Feb 2017 1  
A helper class to run functions in an asynchronous pattern using the Func<T> delegate

Introduction

There are a lot of articles describing the benefits of Func<T> delegates. What I'm attempting to provide here is a helper class which allows an existing method to be run asynchronously and the value returned directly or passed via a callback delegate.

Background

I was tasked to write a DLL to consume a web API. I began by writing an interface with the methods I'd need and implementing the interface in a class. The class I was writing needed these requirements, each method should be asynchronous, and after finishing, pass the response to a callback delegate to be consumed by the calling application. Here's a typical example of just one of the methods:

public virtual async Task Update(UpdateRequest ur, After a)
{
    var response = new Response();

    try
    {
        // The UpdateRequest finalizes the clients application and a payment request
        // is authorized.  This method is awaitable for responsiveness in the client
        // application.
        e.Status = await Task.Run(() =>
        {
            return service.UpdateApplication(ur);
        });
    }
    catch (Exception ex)
    {
        throw;
    } 
    finally
    {
        a?.Invoke(this, response);
    }
}

After I'd finished writing all the necessary methods, I quickly noticed how each one was very similar:

  1. Each was wrapped in a try catch.
  2. Each implemented an await Task.
  3. Each invoked a callback delegate with the response.
  4. Each used a new Response class.

I thought about this for a while. Wouldn't it be nice if I wrote my methods without a try catch block, without invoking a callback delegate and without awaitable code in every method. Also what about the ability to call a method directly and receive the response. Something like this:

public virtual async Task Update(UpdateRequest ur)
{
    return service.UpdateApplication(ur);
}

The method is simplified already. Now, how to use generics to consume each method passing whatever as the method parameter and receiving whatever as the method return type.

Creating Actor Helper Class

First of all, here's the code to create the generic Actor class.

public class Actor<T, V>
{
    // Optional delegate to use to pass back the 
    public delegate void After(object sender, V e);
    
    // use this delegate to represent a method that can be passed
    // as a parameter without explicitly declaring a custom delegate.
    private Func<T, V> job; 

    public Actor(Func<T, V> f)
    {
        job = f;
    }

    // This method passes T as the parameter to Func<T, V> job and 
    // returns V.  The callback delegate is invoked once the Task has
    // ran to completion.
    public virtual async Task Act(T t, After a)
    {
        V v = await Task.Run(() =>
        {
            return job(t);
        });
            
        a?.Invoke(this, v);
    }

    // This method is the same as above but without invoking a
    // callback delegate. The response is returned directly to
    // to the calling application.
    public virtual async Task<V> Act(T t)
    {
        return await Task.Run(() =>
        {
            return job(t);
        });    
    }
}

I can use this Actor class in many scenarios making any procedural code asynchronous but still retaining control over the response. Here's a simplified approach on how to use the Actor class.

Let's say you have a class named Calculate which has one method named LengthOfString. The add method expects a string as a parameter and simply returns an integer with the length of the input string. I've simulated a long operation by sleeping the thread for 10 seconds.

public class Calculate
{
    public int LengthOfString(string s)
    {
        // sleep the thread to simulate a long operation
        Thread.Sleep(10000);
 
        return s.Length;
    }
}

private async void button1_Click(object sender, EventArgs e)
{
    var calculate = new Calculate();

    // Pass a string as the parameter to calculate.LengthOfString
    // and receive an integer as the response.
    var actor = new Actor<string, int>(calculate.LengthOfString);

    try
    {
        await actor.Act("How long is this string?", StringLength);
    } 
    catch (Exception ex) 
    { 
        MessageBox.Show(ex.Message); 
    }
}

private void StringLength(object sender, int len)
{
    // Show the length of the string in a label control. 
    label1.Text = string.Format("Length of string is {0}.", len);
}

In this example, the label1.Text receives this text "Length of string is 24."

By developing this class, I've increased my knowledge of using Func<T> generic programming, and hopefully it may be of use to you. I've got further reading to do.

Should I expose asynchronous wrappers for synchronous methods?

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here