|
// 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>
internal abstract class AsyncResult : IAsyncResult
{
private AsyncCallback _callback;
private object _state;
private bool _completedSynchronously;
private bool _endCalled;
private Exception _exception;
private bool _isCompleted;
private ManualResetEvent _manualResetEvent;
private 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;
}
}
private 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.
internal 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
internal abstract class TypedAsyncResult<T> : AsyncResult
{
private 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.
internal 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);
}
}
|