I am writing an API in C# and I want to provide both synchronous and asynchronous versions of the publicly available methods. For example, if I have the following function:
public int MyFunction(int x, int y)
{
// do something here
System.Threading.Thread.Sleep(2000);
return x * y;
}
how can I create an asynchronous version of the above method (perhaps BeginMyFunction and EndMyFunction)? Are there different ways to achieve the same result, and what are the benefits of the various approaches?
The generic approach is to use a
delegate
:You could create a version of the method that takes a delegate to callback:
This version isn't as clean as the one using AsyncCallback, but it's a little more type-safe.
Mehrdad Afshari answers your question as best as I could suggest. I would, however, advise against this if at all possible. Unless your business object's sole responsibility is to run things synchronously or asynchronously, you're violating the single responsibility principle by even trying to make it aware of the fact that it could run asynchronously. It's easy enough to do this type of operation in the consuming class using anonymous delegates:
If you have no code to run before or after, you can use a lambda to make it more concise
EDIT
In response to @kshahar's comment below, externalizing asynchronicity is still a good idea. This is a common problem that has been solved using callbacks for decades. Lambdas simply shorten the route, and .Net 4.0 makes it even simpler.
.Net 5 makes it even easier than that, but I'm not familiar enough with it to make a statement beyond that at this point.
First of all, if you're compute-bound, I wouldn't bother. Leave it up to the client to determine whether they want to call you synchronously on the current thread, or asynchronously via ThreadPool.QueueUserWorkItem.
If however, you have some form of I/O in your routine, then it could be beneficial to provide an asynchronous version. You should ensure that your asynchronous version uses the corresponding asynchronous I/O calls. You will also need to implement IAsyncResult and return this from your BeginMyFunction call. See Joe Duffy's implementation here, and some notes on the subtleties of various BCL implementations here.