You seem to have a couple of questions. Let them be processed individually
Making WaitHandle Lazy
Yes, this is the most correct approach. You should do this streaming, but lazy is the way to go.
The trick, though, eliminates WaitHandle. WaitHandle is the IDisposable base and must be deleted in a timely manner. The documentation for IAsycResult does not apply to this case. The best way to do this is in EndInvoke. The documentation for BeginInvoke explicitly states that for each BeginInvoke there must be a corresponding EndInvoke (or BeginRead / EndRead). This is the best place to stay WaitHandle.
How to implement AsyncState?
If you look at the standard BCL API that IAsyncResult returns, most of them take a status parameter. This is usually the value returned from AsyncState (see Socket API Example). It is good practice to include a state variable typed as an object for any BeginInvoke API that returns IAsyncResult. Not necessarily, but good practice.
In the absence of a state variable, a null value is returned.
IsCompleted API
This will depend heavily on the implementation that creates the IAsyncResult. But yes, you must implement this.
Jaredpar
source share