public AwaitableSocketAsyncEventArgs(Socket socket, byte[] buffer)
{
Debug.Assert(socket != null);
Debug.Assert(buffer != null && buffer.Length > 0);
// Store the socket into the base's UserToken. This avoids the need for an extra field, at the expense
// of an object=>Socket cast when we need to access it, which is only once per operation.
UserToken = socket;
// Store the buffer for use by all operations with this instance.
SetBuffer(buffer, 0, buffer.Length);
// Hook up the completed event.
Completed += delegate
{
// When the operation completes, see if OnCompleted was already called to hook up a continuation.
// If it was, invoke the continuation.
Action c = _continuation;
if (c != null)
{
c();
}
else
{
// We may be racing with OnCompleted, so check with synchronization, trying to swap in our
// completion sentinel. If we lose the race and OnCompleted did hook up a continuation,
// invoke it. Otherwise, there's nothing more to be done.
Interlocked.CompareExchange(ref _continuation, s_completedSentinel, null)?.Invoke();
}
};
}