I have come across a number of situations where I need to implement a class
that follows the .NET asynchronous design pattern (see
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconasynchronousprogrammingdesignpattern2.asp)
and which implements its functionality by making asynchronous calls.
In simple cases this is easy to do. For example the
System.Net.Sockets.NetworkStream class does exactly this without creating
any new AsyncResult types, async state objects or intercepting the async
callback. It's BeginRead simple calls BeginReceive on the underlying socket
passing it the same async callback and state it was provided and returning
the same async result.
However, I have occasionally needed something more powerful. I may need to
track some additional state, or intercept the callback for some reason. For
example, my EndFoo may want to know the time at which the corresponding
BeginFoo was called. This means I have to pass some additional data in the
async state, which means I have to create my own AsyncResult type (so the
client sees only the async state they provided) and intercept the callback
to provide the client with the correct AsyncResult etc.
This is a non-trivial amount of additional code, but wouldn't be a big deal
except that it appears to be difficult to setup the data structures
properly. Is there any reason the IAsyncResult returned from a Begin method
should be the same object instance as the IAsyncResult passed into the
corresponding async callback (as opposed to a duplicate instance with the
same behaviour)? If so, then I get a cycle in the data structure which
requires some ugly and complex code to handle correctly. Specifically my
AsyncResult object needs to hold a reference to the inner AsyncResult, which
holds a reference to my asyncState which must hold a reference back to my
AsyncResult (I can provide more detail if desired, I drew some pretty graphs
to convince myself this is true). When setting up this object graph, there
are two different places where the inner AsyncResult must be stored - once
after the inner Begin has completed and once when the callback is invoked
(we don't know which will occur first). Anyway, its possible to do this but
seems ugly and error prone (requires locking etc.).
Does anyone have an elegant example of how to chain async calls that need to
track additional state? Seems like this could be a common design pattern,
and I'm surprised at how complex it appears to be to get it right.
Thanks,
Rick
-------
Rick Byers http://www.kinitos.com/
Kinitos: Distributed .NET smart client management
===================================
This list is hosted by DevelopMentor� http://www.develop.com
Some .NET courses you may be interested in:
NEW! Guerrilla ASP.NET, 26 Jan 2004, in Los Angeles
http://www.develop.com/courses/gaspdotnetls
View archives and manage your subscription(s) at http://discuss.develop.com