Как я могу мгновенно вернуть значения из асинхронного цикла? - PullRequest
2 голосов
/ 27 марта 2019

У меня есть функция асинхронного обнаружения, которая обнаруживает устройства в локальной сети, которые я вызываю по нажатию кнопки.Я отправляю широковещательное сообщение на все устройства и слушаю ответы в течение 5 секунд, используя CancellationTokenSource.После того, как токен истек, я возвращаю IEnummerable проанализированных ответов на мою модель WPF.

Я бы хотел вернуть входящие ответы напрямую (и прекратить прослушивание через 5 секунд), чтобы я мог мгновенно отображать обнаруженные устройства впользовательский интерфейс вместо того, чтобы показывать их все через 5 секунд.

Это мой код:

public async Task<IEnumerable<IDevice>> Discover()
    {
        var client = new MyClient();
        var responseData = await GetResponseData(client);
        return this.ParseResponseData(responseData);
    }

    private IEnumerable<IDevice> ParseResponseData(List<DeviceResponseData> responseData)
    {
        foreach (var data in responseData)
        {
            yield return DeviceFactory.Create(data);
        }
    }

    private static async Task<List<DeviceResponseData>> GetResponseData(MyClient client, int timeout = 5000)
    {
        var cancellationToken = new CancellationTokenSource(timeout);
        var data = new List<DeviceResponseData>();

        // ... prepare message and send it
        await client.SendAsync(message, new CancellationToken());

        try
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                // Wait indefinitely until any message is received.
                var response = await client.ReceiveAsync(cancellationToken.Token);

                data.Add(new DeviceResponseData(/* ... */ response));
            }
        }
        catch (TaskCanceledException e)
        {

        }

        return data;
    }

1 Ответ

0 голосов
/ 27 марта 2019

Немного неясно, о чем вы спрашиваете ... Хотя, если вы хотите показывать результаты по мере их поступления. Есть много способов достижения этого, например разъединенные сообщения , события , т. Д.

Тем не менее, вы можете просто использовать простой Action

private static async Task<List<DeviceResponseData>> GetResponseData(MyClient client, Action<DeviceResponseData> update, int timeout = 5000)
{
   var cancellationToken = new CancellationTokenSource(timeout);
   ...
   while (!cancellationToken.IsCancellationRequested)
   {
      // Wait indefinitely until any message is received.
      var response = await client.ReceiveAsync(cancellationToken.Token);

      var result = new DeviceResponseData( /* ... */ response);

      data.Add(result);
      update(result);

   }
   ...
}

использование

var allResults =  await GetResponseData(client,data => UdpateUI(data), timeout);

Примечание : поскольку в этом шаблоне асинхронного ожидания вам не нужно маршалировать результат из Action обратно в контекст пользовательского интерфейса, если он был вызван из

...