Подтвердить что ты не робот

Существует ли общий способ синхронизации асинхронного метода?

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

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

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

Есть ли способ написать вспомогательный метод для этого? Я могу пройти в Action для выполнения, но я не уверен, как передать что-то, что позволяет вспомогательному методу знать, какое событие прослушивать, поскольку не похоже, что вы можете передать 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));
    }
}
4b9b3361

Ответ 1

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

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();
}

Ответ 2

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

    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();
    }

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

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