I have a much longer article in mind for this and will be publishing it out soon. But to quickly answer this let us use an implementation from the framework itself using a delegate. Please note, this is for a usage pattern sample only since all that a delegate does is put the work on the CLR’s thread pool which means more latency for non-blocking work.
Lets create a driver for our async operation which will define our little piece of work. Here we just return a string.
class AyncOperation
{
// Your
delegate to simulate an AsyncResult implementation
static Func<
string> operation = () => "Hello operation.";
internal static IAsyncResult BeginOperation(AsyncCallback callback, object state)...
internal static string EndOperation(IAsyncResult result)...
}
This is what is expected on the 2 paths that the code can complete on.
- Synchronous Path
- IAsyncResult result = BeginOperation()
- Is Result.CompletedSynchronously == true
- Yes
- Handle the completion like calling end etc.
- Handle exceptions.
- No
- Callback
- IS Result.CompletedSynchronously == true
- Yes
- return as the sync path will take care of the rest
- NO
- Handle the completion
- Handle exception if any
So here is the end to end implementation.
namespace Microsoft.Samples.SimpleDelegateAsyncResult
{
using System;
using System.Threading;
class Program
{
static AsyncCallback onCallback = new AsyncCallback(Callback);
ManualResetEvent waitHanlde = new ManualResetEvent(false);
static void Main(string[] args)
{
Program state = new Program();
try
{
IAsyncResult result = AyncOperation.BeginOperation(onCallback, state);
if (result.CompletedSynchronously)
{
state.HandleCompletion(result);
}
}
catch (Exception exception)
{
Console.WriteLine(" Exception : " + exception.Message);
// Do the same exception handling here.
state.waitHanlde.Set();
}
state.waitHanlde.WaitOne();
state.waitHanlde.Close();
Console.WriteLine("Completed");
}
static void Callback(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
Program thisPtr = result.AsyncState as Program;
Exception completionException = null;
try
{
thisPtr.HandleCompletion(result);
}
catch (Exception ex)
{
// Don't throw as you cannot bubble up exceptions on a callback thread
completionException = ex;
}
finally
{
if (completionException != null)
{
// you need to handle exception here as well
Console.WriteLine("Callback Exception : " + completionException.Message);
}
//release the main thread;
thisPtr.waitHanlde.Set();
}
}
void HandleCompletion(IAsyncResult result)
{
Console.WriteLine(AyncOperation.EndOperation(result));
//throw new InvalidOperationException("test exception");
Thread.Sleep(100);
}
}
class AyncOperation
{
// Your delegate to simulate an AsyncResult implementaion
static Func<string> operation = () => "Hello operation.";
internal static IAsyncResult BeginOperation(AsyncCallback callback, object state)
{
return operation.BeginInvoke(callback, state);
}
internal static string EndOperation(IAsyncResult result)
{
return operation.EndInvoke(result);
}
}
}