Остановить ожидание (Task.Delay(-1)) после вызова события

у меня такой код

public async Task DoStuff()
{
    _client.Ready += () => client_Ready("test");

    await Task.Delay(-1);
}

private async Task client_Ready(string message)
{
    await _client.SendMessageAsync(message);
}

как я могу сказать, что после того, как client_Ready вызывается один раз, весь DoStuff должен завершиться/выполнить возврат вместо ожидания?

Есть ли «хороший» способ сделать это, или мне нужно поработать, например, создать исключение и поймать его «выше»?

МРЭ:

using System;
using System.Threading.Tasks;

public class Program
{
    public static async Task RandomlyDelayedStuff()
    {
        Console.WriteLine("this ended");
        await Task.Delay(200);
    }

    public static async Task DoStuff()
    {
        var rnd = new Random();

        await Task.Delay(rnd.Next(0, 5000)).ContinueWith(async task =>
        {
            await RandomlyDelayedStuff();
        });

        await Task.Delay(-1);
    }
    public static async Task Main()
    {
        await DoStuff();
        Console.WriteLine("ended");
    }
}

Я не понимаю, чего должен достичь ваш await Task.Delay(-1);. Что будет, если просто удалить его?

Pac0 21.12.2020 00:55

Я не понимаю вопроса. Вы говорите: «Я не хочу DoStuff возвращаться, пока client_Ready не завершит выполнение»? Если да - зачем тебе это?

mjwills 21.12.2020 00:56

Пожалуйста, поделитесь минимально воспроизводимым примером.

mjwills 21.12.2020 00:57

@mjwills Я подключаюсь к client, который через некоторое время X возвращает мне ответ и вызывает Ready (метод client_Ready). Я использовал Task.Delay(-1), поэтому программа не выходит из функции DoStuff мгновенно (до того, как я получил Ready). Проблема в том, что он никогда не покидает его даже после того, как событие было вызвано

Axelly 21.12.2020 00:57

Да, пожалуйста, предоставьте MRE, потому что эта часть необходимости «не выходить DoStuff» не имеет для меня смысла. Вы назначили обработчик события, вам просто нужно, чтобы обработчик был вызван, я не понимаю, почему это проблема, которая DoStuff сразу заканчивается.

Pac0 21.12.2020 01:01

Вы создаете задачу и просите ее ждать бесконечно. Вы имели в виду применить это к задаче, возвращенной client_Ready, которую вы сейчас игнорируете?

stuartd 21.12.2020 01:01

Вероятно, вы захотите использовать TaskCompletionSource здесь dotnetfiddle.net/gnfH5C

TheGeneral 21.12.2020 01:09
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
3
7
258
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Используйте токен отмены. Передайте токен вызову задержки. Вы можете создать CancellationTokenSource и вызвать для него отмену, которая инициирует отмену вызова для токена.

CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

public async Task DoStuff()
{
    _client.Ready += () => client_Ready("test");

    await Task.Delay(-1, cancelTokenSource.Token);

    // do something else here if desired
}

private async Task client_Ready(string message)
{
    await _client.SendMessageAsync(message);
    cancelTokenSource.Cancel();
}

Вы должны быть в состоянии сделать это с помощью токена отмены.

Код не проверен, я сделал это с задержкой и с помощью отмены для сброса, но никогда с бесконечным таймером и отменой.

const int cDelayMS = -1;
private System.Threading.CancellationTokenSource mCancel = new();

DoStuff()
{
    Task.Delay(cDelayMS, mCancel.Token).ContinueWith(
                async antecedent =>
                {
                    if (antecedent.Status == TaskStatus.Canceled)
                    {
                        // do whatever here
                    }
                });
}

Другие вопросы по теме