|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Threading;
/// <summary>
/// A generic base class for IAsyncResult implementations
/// that wraps a ManualResetEvent.
/// </summary>
abstract class AsyncResult : IAsyncResult
{
AsyncCallback callback;
object state;
bool completedSynchronously;
bool endCalled;
Exception exception;
bool isCompleted;
ManualResetEvent manualResetEvent;
object thisLock;
protected AsyncResult(AsyncCallback callback, object state)
{
this.callback = callback;
this.state = state;
this.thisLock = new object();
}
public object AsyncState
{
get
{
return state;
}
}
public WaitHandle AsyncWaitHandle
{
get
{
if (manualResetEvent != null)
{
return manualResetEvent;
}
lock (ThisLock)
{
if (manualResetEvent == null)
{
manualResetEvent = new ManualResetEvent(isCompleted);
}
}
return manualResetEvent;
}
}
public bool CompletedSynchronously
{
get
{
return completedSynchronously;
}
}
public bool IsCompleted
{
get
{
return isCompleted;
}
}
object ThisLock
{
get
{
return this.thisLock;
}
}
// Call this version of complete when your asynchronous operation is complete. This will update the state
// of the operation and notify the callback.
protected void Complete(bool completedSynchronously)
{
if (isCompleted)
{
// It is a bug to call Complete twice.
throw new InvalidOperationException("Cannot call Complete twice");
}
this.completedSynchronously = completedSynchronously;
if (completedSynchronously)
{
// If we completedSynchronously, then there is no chance that the manualResetEvent was created so
// we do not need to worry about a race condition.
Debug.Assert(this.manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult.");
this.isCompleted = true;
}
else
{
lock (ThisLock)
{
this.isCompleted = true;
if (this.manualResetEvent != null)
{
this.manualResetEvent.Set();
}
}
}
// If the callback throws, there is a bug in the callback implementation
if (callback != null)
{
callback(this);
}
}
// Call this version of complete if you raise an exception during processing. In addition to notifying
// the callback, it will capture the exception and store it to be thrown during AsyncResult.End.
protected void Complete(bool completedSynchronously, Exception exception)
{
this.exception = exception;
Complete(completedSynchronously);
}
// End should be called when the End function for the asynchronous operation is complete. It
// ensures the asynchronous operation is complete, and does some common validation.
protected static TAsyncResult End<TAsyncResult>(IAsyncResult result)
where TAsyncResult : AsyncResult
{
if (result == null)
{
throw new ArgumentNullException("result");
}
TAsyncResult asyncResult = result as TAsyncResult;
if (asyncResult == null)
{
throw new ArgumentException("Invalid async result.", "result");
}
if (asyncResult.endCalled)
{
throw new InvalidOperationException("Async object already ended.");
}
asyncResult.endCalled = true;
if (!asyncResult.isCompleted)
{
asyncResult.AsyncWaitHandle.WaitOne();
}
if (asyncResult.manualResetEvent != null)
{
asyncResult.manualResetEvent.Dispose();
}
if (asyncResult.exception != null)
{
throw asyncResult.exception;
}
return asyncResult;
}
}
//An AsyncResult that completes as soon as it is instantiated.
class CompletedAsyncResult : AsyncResult
{
public CompletedAsyncResult(AsyncCallback callback, object state)
: base(callback, state)
{
Complete(true);
}
public static void End(IAsyncResult result)
{
AsyncResult.End<CompletedAsyncResult>(result);
}
}
//A strongly typed AsyncResult
abstract class TypedAsyncResult<T> : AsyncResult
{
T data;
protected TypedAsyncResult(AsyncCallback callback, object state)
: base(callback, state)
{
}
public T Data
{
get { return data; }
}
protected void Complete(T data, bool completedSynchronously)
{
this.data = data;
Complete(completedSynchronously);
}
public static T End(IAsyncResult result)
{
TypedAsyncResult<T> typedResult = AsyncResult.End<TypedAsyncResult<T>>(result);
return typedResult.Data;
}
}
//A strongly typed AsyncResult that completes as soon as it is instantiated.
class TypedCompletedAsyncResult<T> : TypedAsyncResult<T>
{
public TypedCompletedAsyncResult(T data, AsyncCallback callback, object state)
: base(callback, state)
{
Complete(data, true);
}
public new static T End(IAsyncResult result)
{
TypedCompletedAsyncResult<T> completedResult = result as TypedCompletedAsyncResult<T>;
if (completedResult == null)
{
throw new ArgumentException("Invalid async result.", "result");
}
return TypedAsyncResult<T>.End(completedResult);
}
}
|