Асинхронная функция, выполняющая асинхронные вызовы
У меня есть библиотека, которая использует асинхронный шаблон BeginXxx EndXxx (очевидно, следующий код упрощен):
ILibrary
{
IAsyncResult BeginAction(string name, AsyncCallback callback, object state);
int EndAction(IAsyncResult asyncResult, out object state)
}
Я пытаюсь создать класс, который использует эту библиотеку и реализует тот же шаблон сам:
Manager
{
private ILibrary library;
public IAsyncResult BeginMultipleActions(IEnumerable<string> names,
AsyncCallback callback, object state)
{
var handles = new List<IAsyncResult>();
foreach(string name in names)
{
var handle = library.BeginAction(name, OnSingleActionCompleted, null);
handles.Add(handle);
}
//???
}
public int EndMultipleActions(IAsyncResult asyncResult, out object state)
{
//???
}
private void OnSingleActionCompleted(IAsyncResult asyncResult)
{
//???
}
}
Я пробовал пару решений (используя ManualResetEvent), но я нахожу мой код очень уродливым. Какой самый чистый способ сделать это (в C#3.5) без потери функциональности (обратный вызов, дескриптор ожидания, ...)?
2 ответа
Чтобы иметь возможность успешно реализовать шаблон, который вы описываете, вы должны быть в состоянии вызвать обратный вызов, переданный в ваш BeginMultipleActions
метод после того, как все отдельные действия завершены. Использование событий и ожидание их может победить вашу единственную цель - выполнять асинхронные вызовы, поскольку они блокируют потоки. Обратный вызов, который вы передаете в одно действие, должен быть в состоянии выяснить, когда все методы завершены, а затем вызвать обратный вызов, предоставленный вашим клиентом BeginMultipleActions
метод. Вот пример, который может сделать это для вас (я не проверял это). Тем не менее, это только для начала и далеко не идеально. Там будет несколько нюансов, которые вам придется проработать.
interface ILibrary
{
IAsyncResult BeginAction(string name, AsyncCallback callback, object state);
int EndAction(IAsyncResult asyncResult, out object state);
}
class Manager
{
private ILibrary library;
class AsyncCallInfo : IAsyncResult
{
public int PendingOps;
public AsyncCallback Callback { get; set; }
public object AsyncState { get; set; }
public WaitHandle AsyncWaitHandle
{
// Implement this if needed
get { throw new NotImplementedException(); }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return PendingOps == 0; }
}
}
public IAsyncResult BeginMultipleActions(IEnumerable<string> names,
AsyncCallback callback, object state)
{
var callInfo = new AsyncCallInfo {
Callback = callback,
AsyncState = state
};
callInfo.PendingOps = names.Count();
foreach (string name in names)
{
library.BeginAction(name, ar => OnSingleActionCompleted(ar, callInfo), null);
}
return callInfo;
}
public int EndMultipleActions(IAsyncResult asyncResult, out object state)
{
// do your stuff
state = asyncResult.AsyncState;
return 0;
}
private void OnSingleActionCompleted(IAsyncResult asyncResult, AsyncCallInfo callInfo)
{
//???
Interlocked.Decrement(ref callInfo.PendingOps);
if (callInfo.PendingOps == 0)
{
callInfo.Callback(callInfo);
}
}
}
Я предлагаю вам взглянуть на AsyncEnumerator Джеффри Рихтера. Это упрощает написание асинхронного кода и поддерживает несколько шаблонов асинхронных реализаций - http://msdn.microsoft.com/en-us/magazine/cc546608.aspx
Используйте beginInvok для запуска асинхронной операции. Он поддерживает обратные вызовы.
Более детально: