События - асинхронны? Как затормозить обработчик события так, чтобы не остановить все остальное?

У меня есть два класса, которые общаются с помощью событий. Обработчик события в классе Bot, которое приходит из внешнего источника:

        private void OnOrder(Order order)
        {
            if (order.Account == Tool.AccountID && order.SecCode == Tool.SecurityCode && order.State == State.Completed) 
            {
                Task.Delay(50); // здесь нужно подождать 
                Strategy.ProcessingExecutedOrders(order);
            }
        }

Метод в классе Bot, в котором вызывается событие NewDeal:

private void SendOrders(ref Deal deal)
        {
              // что-то происходит
              // асинхронный метод, после которого может прийти событие OnOrder, а может и не прийти
              temp_order = QuikConnecting.LimitOrder(Tool, deal.OrdersInfo[i].Operation, deal.OrdersInfo[i].Price, deal.OrdersInfo[i].Vol).Result; 
              if (temp_order != null)
              {
                   deal.OrdersInfo[i].IDOrder = temp_order.OrderNum;
                   deal.OrdersInfo[i].IssueStatus = State.Completed;
                   deal.Status = StatusDeal.Open;
                   NewDeal?.Invoke(deal, Command.SendOrder); // вызываю другое событие, которое передает объект в другой класс
              }
              // что-то происходит
        }

Проблема в том, что событие OnOrder может прийти раньше, чем произойдет NewDeal?.Invoke. И мне нужно чтобы OnOrder ждал хоть какое-то время, но Task.Delay не работает. В связи с этим вопрос, как тормознуть обработчик события OnOrder так, чтобы метод SendOrders продолжил работать?


Ответы (1 шт):

Автор решения: aepot

Вот эту цитату от @tym32167 надо высечь в камне.

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


Если вопрос только про ожидание, то у вас всего 2 опции ожидания:

  1. Синхронное
private void OnOrderAsync(Order order)
{
    if (order.Account == Tool.AccountID && order.SecCode == Tool.SecurityCode && order.State == State.Completed) 
    {
        Thread.Sleep(50);
        Strategy.ProcessingExecutedOrders(order);
    }
}
  1. Асинхронное
private async Task OnOrder(Order order)
{
    if (order.Account == Tool.AccountID && order.SecCode == Tool.SecurityCode && order.State == State.Completed) 
    {
        await Task.Delay(50);
        Strategy.ProcessingExecutedOrders(order);
    }
}

Разница в том, что первое блокирует вызывающий поток на время ожидания, в второе - нет.

Как вы уже наверное поняли, вы просто неправильно использовали Task.Delay.


Так же у вас ошибка в использовании асинхронной операции, вы ее вызываете синхронно, что в принципе противоречит принципам асинхронности

// делаем метод асинхронным - вызывать так: await SendOrdersAsync(...);
private async Task SendOrdersAsync(ref Deal deal)
{
    // ...
    temp_order = await QuikConnecting.LimitOrder(Tool, deal.OrdersInfo[i].Operation, deal.OrdersInfo[i].Price, deal.OrdersInfo[i].Vol); 
    if (temp_order != null)
    {
        deal.OrdersInfo[i].IDOrder = temp_order.OrderNum;
        deal.OrdersInfo[i].IssueStatus = State.Completed;
        deal.Status = StatusDeal.Open;
        NewDeal?.Invoke(deal, Command.SendOrder);
    }
    // ...
}

Никогда не используйте .Wait() или .Result для асинхронных операций. Это ошибка, которая 1) вешает вам поток, 2) может привести к взаимоблокировке потоков - дедлоку.

Неисключено, что после того как вы поправите ошибку вызова асинхронного метода, ваши события заработают как надо, и не придется втыкать костыли типа Task.Delay.

Почитайте: Асинхронное программирование.

→ Ссылка