SoFunction
Updated on 2025-03-04

How to use Task in C#

Preface

In C#, Task represents an asynchronous operation. It allows you to perform time-consuming operations without blocking the main thread, thereby improving application responsiveness and performance. This tutorial will introduce Task in C# in detail.

Basic concepts of Task

Task is an asynchronous programming model introduced by .NET Framework 4.0, which represents an operation that may not have been completed.

Task can represent any asynchronous operations, such as file reading, network request, database query, etc. Compared with the traditional asynchronous programming model, Task provides a more concise and efficient way to handle asynchronous operations.

Create Task

Using an asynchronous method

Asynchronous methods in C# usually start with the async keyword and return a Task or Task.

For example:

   async Task<int> CalculateSumAsync()
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   }

In this example, the CalculateSumAsync method is an asynchronous method that returns a Task representing an asynchronous operation that calculates the sum of integers from 0 to 99 and returns the result.

How to use

Methods can take a delegate as a parameter and execute the delegate on a new thread.

For example:

   Task<int> task = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   });

In this example, the method takes a lambda expression as a parameter that calculates the sum of integers from 0 to 99 and returns the result.

The method returns a Task, indicating the asynchronous operation performed on a new thread.

Wait for Task to complete

Use the await keyword

The await keyword is used to wait for a Task to complete. When waiting for a Task using the await keyword, the current method will pause execution until the Task is completed.

For example:

   async Task<int> CalculateSumAsync()
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   }

   async Task Main()
   {
       int result = await CalculateSumAsync();
       (result);
   }

In this example, the Main method is an asynchronous method that calls the CalculateSumAsync method and waits for the method to complete using the await keyword.

Once the CalculateSumAsync method is completed, the result variable will be assigned to the return value of the method and the result will be output on the console.

How to use

Method is used to wait for a Task to complete. Unlike the await keyword, the method blocks the current thread until the Task completes.

For example:

   Task<int> task = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   });

   ();
   int result = ;
   (result);

In this example, the () method blocks the current thread until the task completes.

Once the task is completed, the result variable will be assigned as the return value of the task and the result will be output on the console.

Handle Task exceptions

Use the try-catch block

When waiting for a Task, you can use the try-catch block to catch exceptions that occur in the Task.

For example:

   async Task<int> CalculateSumAsync()
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       throw new Exception("An error occurred.");
       return sum;
   }

   async Task Main()
   {
       try
       {
           int result = await CalculateSumAsync();
           (result);
       }
       catch (Exception ex)
       {
           ();
       }
   }

In this example, the CalculateSumAsync method throws an exception during the calculation of the sum.

In the Main method, use the try-catch block to catch this exception and output an exception message on the console.

Use Properties

The property returns an AggregateException containing all exceptions that occur in the Task.

For example:

   Task<int> task = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       throw new Exception("An error occurred.");
       return sum;
   });

   try
   {
       ();
       int result = ;
       (result);
   }
   catch (AggregateException ex)
   {
       foreach (var innerException in )
       {
           ();
       }
   }

In this example, the () method blocks the current thread until the task completes.

If an exception occurs in the task, the catch block will catch the AggregateException and iterate through all exceptions in it, outputting an exception message on the console.

Task's continuation

Use the ContinueWith method

The ContinueWith method is used to perform another operation after one Task is completed.

For example:

   Task<int> task = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   });

   (t =>
   {
       ();
   });

In this example, the method executes a lambda expression after the task is completed, which outputs the result of the task.

Use await keywords and asynchronous methods

You can also use the await keyword and asynchronous method to achieve the continuation of Task.

For example:

   async Task<int> CalculateSumAsync()
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   }

   async Task PrintResultAsync(int result)
   {
       (result);
   }

   async Task Main()
   {
       int result = await CalculateSumAsync();
       await PrintResultAsync(result);
   }

In this example, the Main method first calls the CalculateSumAsync method and waits for the method to complete using the await keyword. It then calls the PrintResultAsync method and waits for the method to complete using the await keyword.

In this way, the PrintResultAsync method is executed as a continuation of the CalculateSumAsync method.

Parallel execution of Task

Using multiple tasks

Multiple Tasks can be started at the same time and wait for them to complete.

For example:

   Task<int> task1 = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   });

   Task<int> task2 = (() =>
   {
       int product = 1;
       for (int i = 1; i <= 10; i++)
       {
           product *= i;
       }
       return product;
   });

   (task1, task2);
   int sum = ;
   int product = ;
   (sum);
   (product);

In this example, two Tasks are initiated simultaneously, one computes the sum of integers from 0 to 99, and the other computes the product of integers from 1 to 10. Then, use the method to wait for all of these two tasks to complete and output the result.

How to use

The method returns a Task, which is completed only when all incoming Tasks are completed.

For example:

   Task<int> task1 = (() =>
   {
       int sum = 0;
       for (int i = 0; i < 100; i++)
       {
           sum += i;
       }
       return sum;
   });

   Task<int> task2 = (() =>
   {
       int product = 1;
       for (int i = 1; i <= 10; i++)
       {
           product *= i;
       }
       return product;
   });

   Task<int[]> tasks = (task1, task2);
   int[] results = await tasks;
   int sum = results[0];
   int product = results[1];
   (sum);
   (product);

In this example, use the method to wait for both tasks to complete and return an array containing the results of two tasks. Then, use the await keyword to wait for this task to complete and output the result.

Summarize

Task is a powerful asynchronous programming model in C# that allows you to perform time-consuming operations without blocking the main thread.

By using Task, you can improve the responsiveness and performance of your application while keeping your code concise and readable.

The above is personal experience. I hope you can give you a reference and I hope you can support me more.