I'm implementing a library with some APM methods that do asynchronous I/O. (To get it out of the way, I cannot use Tasks, async/await, Rx, third-party libraries, etc.)
Say one of my APM library methods, BeginOuter()
, is just deferring to another APM method, BeginInner()
, to do its asynchronous I/O. Is there any reason I can't reuse the inner IAsyncResult
from BeginInner()
as the outer IAsyncResult
from BeginOuter()
, if everything else I'm doing with the user's input is synchronous? Such as:
// Omitting non-APM parameters for clarity; assume these methods do synchronous work on some other input.
public IAsyncResult BeginOuter(InputStuff stuff, AsyncCallback callback, object state)
{
return BeginInner(stuff, result =>
{
callback(result);
}, state);
}
public OutputStuff EndOuter(IAsyncResult result)
{
EndInner(result);
// Do some synchronous work to get OutputStuff.
return MakeOutputStuff();
}
Obviously, if BeginOuter()
were chaining together multiple asynchronous calls to do its work, it'd be a mistake to hand the caller back only the first one to wait on. But what if there's just a single asynchronous call?
Also, in my case, there's nothing I can think of that the caller can mess up after BeginInner()
completes but before they call EndOuter()
-- they're going to be depending on the results of EndOuter()
to do anything useful.
Just having a hard time integrating all the information on this that's out there. I've seen several implementations of the IAsyncResult pattern, but I can't find much about this particular use case, apart from: http://mtaulty.com/communityserver/blogs/mike_taultys_blog/archive/2005/02/21/5279.aspx Would love to understand the subtleties a little better.
Edit: I did see this question, but the responses at the time I checked were all "use [library]", "do it differently", or "implement IAsyncResult" (but without going into the why). I'm trying to understand if this is ever an acceptable thing to do, or if implementing IAsyncResult is the only game in town.
Piggybacking a bit of synchronous code on a single operation like that will work.
Probably best if the code you add doesn't block, which the caller might not expect.
Not passing the state
parameter to the inner operation is a bit naughty - you should probably omit it from your Begin...
method signature, or pass it on if you can.