Question

I have a library that uses the BeginXxx EndXxx asynchronous pattern (obviously, the following code is simplified):

ILibrary
{
    IAsyncResult BeginAction(string name, AsyncCallback callback, object state);
    int EndAction(IAsyncResult asyncResult, out object state)
}

I'm trying to build a class that uses that library, and that implements the same pattern itself:

Manager
{
    private ILibrary library;

    public IAsyncResult BeginMultipleActions(IEnumerable<string> names, 
                                             AsyncCallback callback, object state)
    {
        var handles = new List<IAsyncResult>();
        foreach(string name in names)
        {
            var handle = library.BeginAction(name, OnSingleActionCompleted, null);
            handles.Add(handle);
        }
        //???
    }
    public int EndMultipleActions(IAsyncResult asyncResult, out object state)
    {
        //???
    }

    private void OnSingleActionCompleted(IAsyncResult asyncResult)
    {
        //???
    }
}

I've tried a couple of solutions (using ManualResetEvent) but I find my code very ugly. What is the cleanest way to do this (in C#3.5) without losing functionality (callback, wait handle, ...)?

Was it helpful?

Solution

To be able to successfully implement the pattern you are describing, you should be able to call the callback passed into your BeginMultipleActions method after all single actions are complete. Using events and waiting on them, might defeat your sole purpose of doing async calls as they would block the threads. The callback you pass into the single action should be able to figure out when all the methods are completed and then call the callback supplied by your client to the BeginMultipleActions method. Here's a sample that might do it for you (I haven't tested it). However, this is only to get you started and is far from perfect. There will be several nuances that you will have to work through.

interface ILibrary
{
    IAsyncResult BeginAction(string name, AsyncCallback callback, object state);
    int EndAction(IAsyncResult asyncResult, out object state);
}

class Manager
{
    private ILibrary library;

    class AsyncCallInfo : IAsyncResult
    {
        public int PendingOps;
        public AsyncCallback Callback { get; set; }
        public object AsyncState { get; set; }

        public WaitHandle AsyncWaitHandle
        {
            // Implement this if needed
            get { throw new NotImplementedException(); }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return PendingOps == 0; }
        }
    }

    public IAsyncResult BeginMultipleActions(IEnumerable<string> names,
                                             AsyncCallback callback, object state)
    {
        var callInfo = new AsyncCallInfo {
            Callback = callback,
            AsyncState = state
        };

        callInfo.PendingOps = names.Count();
        foreach (string name in names)
        {
            library.BeginAction(name, ar => OnSingleActionCompleted(ar, callInfo), null);
        }

        return callInfo;
    }

    public int EndMultipleActions(IAsyncResult asyncResult, out object state)
    {
        // do your stuff
        state = asyncResult.AsyncState;
        return 0;
    }

    private void OnSingleActionCompleted(IAsyncResult asyncResult, AsyncCallInfo callInfo)
    {
        //???
        Interlocked.Decrement(ref callInfo.PendingOps);
        if (callInfo.PendingOps == 0)
        {
            callInfo.Callback(callInfo);
        }
    }
}

I suggest you take a look at Jeffrey Richter's AsyncEnumerator. It simplifies writing asynchronous code and supports several patterns of async implementations - http://msdn.microsoft.com/en-us/magazine/cc546608.aspx

OTHER TIPS

Use beginInvok for start asincronous operation. It supports callbacks.

More detail:

http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top