Есть ли общий способ синхронизации асинхронного метода? - PullRequest
11 голосов
/ 13 февраля 2010

У нас есть этот общий сценарий, где у нас есть метод, который выполняет какое-то действие асинхронно и вызывает событие, когда оно выполнено.

Иногда мы хотим, чтобы это делалось синхронно, поэтому у нас есть код, который выглядит примерно так:

ManualResetEvent reset = new ManualResetEvent(false);
someobject.AsyncActionDone += (sender, args) => reset.Set();
someobject.PerformAsyncAction();
reset.WaitOne();

Есть ли способ написать вспомогательный метод для этого? Я могу передать действие для выполнения, но я не уверен, как передать что-то, что позволяет вспомогательному методу знать, какое событие прослушивать, поскольку не похоже, что вы можете передать EventHandler в качестве параметра. *

Предпочтительно решение, которое не требует отражения

Кажется, есть некоторая путаница, это пример того, на что похож класс некоторого объекта:

public class SomeClass
{
    private ExternalServer someServerOverTheNetwork = new ExternalServer();

    public event EventHandler AsyncActionDone;
    public Data SomeData { get; set; }
    public void PerformAsyncAction()
    {
        someServerOverTheNetwork.GetSomeData(OnDataRetrived);
    }

    public Data OnDataRetrived(Data someData)
    {
        AsyncActionDone(this, new DataEventArgs(someData));
    }
}

Ответы [ 2 ]

4 голосов
/ 13 февраля 2010

Я хотел бы рассмотреть реализацию Асинхронного шаблона проектирования в объектах, которые выполняют асинхронную операцию.

public object Operation(object arg)
{
    var ar = BeginOperation(arg, null, null);

    return EndOperation(ar);
}

public IAsyncResult BeginOperation(object arg, AsyncCallback asyncCallback, object state)
{
    AsyncResult asyncResult = new AsyncResult(asyncCallback, state);

    // Lauch the asynchronous operation

    return asyncResult;
}

private void LaunchOperation(AsyncResult asyncResult)
{
    // Do something asynchronously and call OnOperationFinished when finished
}

private void OnOperationFinished(AsyncResult asyncResult, object result)
{
    asyncResult.Complete(result);
}


public object EndOperation(IAsyncResult asyncResult)
{
    AsyncResult ar = (AsyncResult)asyncResult;

    return ar.EndInvoke();
}

С этим шаблоном вы можете иметь несколько одновременных асинхронных операций над вашим объектом.

Примечание. Вы можете легко найти реализацию универсального класса AsyncResult в Интернете.

Edit:

Поскольку вы хотите сохранить текущий дизайн, если весь ваш объект может иметь только одну асинхронную операцию, вы можете определить интерфейс IAsyncOperation и внедрить его во всех ваших объектах.

public interface IAsyncOperation
{
    event EventHandler AsyncActionDone;
    void PerformAsyncAction();
}

Тогда вы могли бы иметь:

public static CallSynchronously(IAsyncOperation asyncOperation)
{
    ManualResetEvent reset = new ManualResetEvent(false);
    asyncOperation.AsyncActionDone += (sender, args) => reset.Set();
    asyncOperation.PerformAsyncAction();
    reset.WaitOne();
}

Если ваши объекты могут содержать несколько асинхронных операций, то, не задумываясь, я думаю, что нет никакого способа достичь того, что вы хотите сделать, но вы все равно можете определить синхронную версию всех асинхронных операций, которая включает ManualResetEvent.

public void PerformAction()
{
    ManualResetEvent reset = new ManualResetEvent(false);
    this.AsyncActionDone += (sender, args) => reset.Set();
    this.PerformAsyncAction();
    reset.WaitOne();
}
3 голосов
/ 13 февраля 2010

Если я уловил ваш дрейф, вы можете просто использовать делегатов следующим образом, создать делегат для вызова функции, давайте вызовем его

    public delegate string AsyncDelegate();

Затем создайте прокси-функцию следующим образом:

 public static void ExecuteSync(AsyncDelegate func)
    {
        ManualResetEvent reset = new ManualResetEvent(false);
        int threadId;
        func.BeginInvoke((a)=>reset.Set(), null);
        reset.WaitOne();
    }

Вот и все, вы можете сделать его немного сложнее, добавив еще один делегат для запуска после завершения или что-то в этом роде.

Наслаждайтесь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...