C# Continuar com

Resumo : neste tutorial, você aprenderá como usar o ContinueWith()método C# da Taskclasse para continuar uma operação assíncrona quando concluída.

Introdução ao método C# ContinueWith()

O programa a seguir demonstra como usar um Taskpara executar uma operação demorada em um thread separado e ainda ser capaz de recuperar o resultado dessa operação no thread principal:

static int GetSquareNumber(int number)
{
    Thread.Sleep(3000);
    return number * number;
}

var result = 0;

var task = Task.Run(() => GetSquareNumber(10));


// block the main thread
result = task.Result;

while (result == 0)
{
    Console.WriteLine("Waiting for the result...");
    Thread.Sleep(1000);
}


Console.WriteLine(result);Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina um método chamado GetSquareNumber()que receba um número inteiro e retorne o número quadrado desse número após um atraso de três segundos. O método usa Thread.Sleep()para pausar o thread atual por três segundos.

Em seguida, o programa cria um novo método Taskusando Task.Run(), que executa o GetSquareNumber()método com um argumento de 10 em um thread separado. O Task.Run()retorna um Taskobjeto armazenado na taskvariável.

Para recuperar o resultado do GetSquareNumber()método, o programa utiliza task.Resulta propriedade, que bloqueia os threads principais até que a tarefa seja concluída e o resultado esteja disponível.

O código dentro do whileloop não é executado porque a resultvariável é zero quando a execução atinge o whileloop.

O motivo é que task.Resultbloqueia o thread principal até que GetSquareNumber()o método retorne o resultado e o atribua à resultvariável.

Para criar uma continuação que será executada de forma assíncrona assim que a tarefa de destino for concluída, você usa o método estático ContinueWith()da Taskclasse.

Por exemplo:

static int GetSquareNumber(int number)
{
    Thread.Sleep(3000);
    return number * number;
}

// main thread
var result = 0;

// create a new task (in a different thread)
var task = Task.Run(() => GetSquareNumber(10));

// create a continuation
task.ContinueWith((task) =>
{
    // a different thread
    result = task.Result;
    Console.WriteLine($"Result:{result}");
});


while (result == 0)
{
    Console.WriteLine("Waiting for the result...");
    Thread.Sleep(1000);
}Linguagem de código:  C#  ( cs )

Saída:

Waiting for the result...
Waiting for the result...
Waiting for the result...
Result:100Linguagem de código:  texto simples  ( texto simples )

Neste exemplo, o thread principal grava uma mensagem no console 3 vezes, cada uma por segundo, até que a tarefa seja concluída.

O ContinueWith()método a seguir cria uma continuação quando a tarefa é concluída. Ele executa um método que atribui o resultado da tarefa à resultvariável e o grava no console.

Encadeamento de tarefas

Se você tiver várias operações assíncronas que precisam ser executadas em uma ordem específica e quiser iniciar uma operação após a conclusão de outra operação, poderá usar uma técnica conhecida como encadeamento de operações assíncronas ou encadeamento de tarefas.

O programa a seguir demonstra como encadear tarefas usando o ContinueWith()método:

using static System.Console;

var t1 = Task.Run(() => 5);
var t2 = t1.ContinueWith(t => t.Result * 2);
var t3 = t2.ContinueWith(t => t.Result + 10);


t3.ContinueWith(t => WriteLine(t.Result));

// wait for the tasks to complete
Read();Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, crie uma nova Taskchamada t1que retorne o valor inteiro 5usando o Task.Run()método.

A seguir, crie uma nova Taskchamada t2chamando o ContinueWith()método em task t1. A expressão lambda passada ao ContinueWith()método especifica que o resultado de t1deve ser multiplicado por 2.

Em seguida, crie uma nova Taskchamada t3chamando o ContinueWith()método on t2. A expressão lambda especifica que o resultado de t2deve ser incrementado em 10.

Depois disso, use o ContinueWith()método para aguardar t3a conclusão e grave o resultado final no console usando o WriteLine()método.

Por fim, use o Read()método para aguardar a conclusão das tarefas antes de o programa encerrar. Isso garante que a saída seja exibida no console antes do término do programa.

Como os ContinueWith()retornos a Task, você pode encadeá-los assim para tornar o código mais conciso:

using static System.Console;

Task.Run(() => 5)
    .ContinueWith(t => t.Result * 2)
    .ContinueWith(t => t.Result + 10)
    .ContinueWith(t => WriteLine(t.Result));

// wait for the tasks to complete
Read();Linguagem de código:  C#  ( cs )

Opções de continuação

Às vezes, você deseja criar uma continuação com base no fato de a tarefa ter sido concluída com êxito ou com falha, ou ambos. O método ContinueWith() possui um segundo parâmetro do tipo TaskContinuationOptions que permite fazer isso.

O exemplo a seguir mostra como usar o método ContinueWith com TaskContinuationOptions

using static System.Console;

static int GetRandomNumber(int min, int max)
{
    if (min >= max)
    {
        throw new ArgumentException($"The {min} must less than {max}");
    }

    Thread.Sleep(1000);
    return new Random().Next(min, max);
}

static int GetInt(string message)
{
    int n = 0;
    while (true)
    {
        Write(message);
        string? input = ReadLine();
        if (int.TryParse(input, out n))
        {
            return n;
        } 
    }
}

int min = GetInt("Enter the min integer:");
int max = GetInt("Enter the max integer:");

var task = Task.Run(() => GetRandomNumber(min, max));

// continue if ran to completion
task.ContinueWith(t =>
{
    WriteLine($"Result: {t.Result}");
},
TaskContinuationOptions.OnlyOnRanToCompletion);

// continue if only faulted
task.ContinueWith(t =>
{
    WriteLine($"The task completed with the {task.Status} status");
},
TaskContinuationOptions.OnlyOnFaulted);

Read();Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina o método GetRandomNumber() que retorna um número aleatório entre mínimo e máximo após um atraso de um segundo. Lança uma exceção se o mínimo for maior que o máximo:

static int GetRandomNumber(int min, int max)
{
    if (min >= max)
    {
        throw new ArgumentException($"The {min} must less than {max}");
    }

    Thread.Sleep(1000);
    return new Random().Next(min, max);
}Linguagem de código:  C#  ( cs )

Segundo, defina o método GetInt() que retorna um número inteiro da entrada do usuário:

static int GetInt(string message)
{
    int n = 0;
    while (true)
    {
        Write(message);
        string? input = ReadLine();
        if (int.TryParse(input, out n))
        {
            return n;
        } 
    }
}Linguagem de código:  C#  ( cs )

Terceiro, solicite ao usuário os números inteiros mínimo e máximo:

int min = GetInt("Enter the min integer:");
int max = GetInt("Enter the max integer:");Linguagem de código:  C#  ( cs )

Quarto, crie uma tarefa que retorne um número inteiro aleatório entre o mínimo e o máximo:

var task = Task.Run(() => GetRandomNumber(min, max));Linguagem de código:  C#  ( cs )

Se o mínimo for menor que o máximo, a tarefa será executada até a conclusão. Caso contrário, será culpado.

Quinto, crie uma continuação se a tarefa for concluída usando o método ContinueWith() com a opção TaskContinuationOptions.OnlyOnRanToCompletion:

task.ContinueWith(t =>
{
    WriteLine($"Result: {t.Result}");
},
TaskContinuationOptions.OnlyOnRanToCompletion);Linguagem de código:  C#  ( cs )

Quinto, crie uma segunda continuação se a tarefa apresentar falha usando o método ContinueWith() com a opção TaskContinuationOptions.OnlyOnFaulted:

// continue if only faulted
task.ContinueWith(t =>
{
    WriteLine($"The task completed with the {task.Status} status");
},
TaskContinuationOptions.OnlyOnFaulted);

Read();Linguagem de código:  C#  ( cs )

Se você inserir valores mínimo e máximo válidos, a primeira continuação será executada e gravará o número aleatório no console:

Enter the min integer:10
Enter the max integer:100
Result: 81Linguagem de código:  texto simples  ( texto simples )

Caso contrário, será executada a segunda continuação que grava uma mensagem de erro no console:

Enter the min integer:100
Enter the max integer:10
The task completed with the Faulted statusLinguagem de código:  texto simples  ( texto simples )

Resumo

  • Use o ContinueWith()método da Taskclasse para criar uma continuação que seja executada de forma assíncrona quando o processo Taskfor concluído.
  • Utilize TaskContinuationOptionspara criar continuações de acordo com o status da tarefa.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *