C# Async/await with a Func delegate
By FoxLearn 1/21/2025 8:31:17 AM 14
Here’s an example of a simple Func that accepts a parameter and returns a Task:
Func<int, Task> delayMessage = async (seconds) => { await Task.Delay(1000 * seconds); Console.WriteLine($"Waited for {seconds} seconds!"); };
In this example, the Func
accepts an int
parameter and returns a Task
. The method waits for the specified number of seconds before printing a message. Since the return type is a Task
, it can be awaited.
await delayMessage(5);
In this case, after 5 seconds, you will see the output: Waited for 5 seconds!
Notice that this delegate doesn't return a value. You would typically use an Action
delegate if no value needs to be returned, but since Action
cannot be awaited, we use Func
with Task
as the return type to make it awaitable.
Awaitable Func Delegate Returning a Value
To create a Func
delegate that is awaitable and returns a value, you use Task<T>
as the return type.
Here’s an example where we calculate the square of a number:
Func<int, Task<int>> calculateSquare = async (num) => { await Task.Delay(100); // Simulating async operation return num * num; };
In this example, the Func
takes an int
parameter and returns a Task<int>
. The result of awaiting this Func
is an integer value, which is the square of the input number.
int result = await calculateSquare(4);
After awaiting, the result will be 16
.
Using an Awaitable Func Delegate in a Strategy Pattern
Imagine you need to fetch records asynchronously from a database, serialize the data to JSON, and save it to a file. However, the way records are fetched differs for each type of data (such as Product
, Customer
, etc.).
In this case, you can use a delegate to handle the fetching logic, ensuring the fetching is done asynchronously using an awaitable Func
delegate.
Here’s how you can define an async method that accepts an awaitable Func
delegate:
private async Task SaveToFile<TRecord>(string filePath, string id, Func<string, Task<TRecord>> fetchData) { var record = await fetchData(id); var json = JsonSerializer.Serialize(record); File.WriteAllText(filePath, json); }
This method takes a Func
delegate as a parameter, which accepts a string
(the id
of the record to fetch) and returns a Task<TRecord>
(a generic type TRecord
). When awaited, it will return a record of the specified type, such as a Product
or Customer
.
For example, if you're working with an Employee
record, you would call the method like this:
await SaveToFile<Employee>(@"C:\temp\employee.json", "12345", async (id) => await EmployeeRepo.Get(id));
In this call, the EmployeeRepo.Get(id)
method fetches the Employee
record by its ID, and the record is then serialized to JSON and saved to the specified file path.