CSharp Task Asynchronous Programming

Last Updated: 10/29/2021

Pass and Retrieve Data From Task

When you use a lambda expression to create a delegate, you have access to all the variables that are visible at that point in your source code.

Accessing ForEach Variables

In foreach loop it captures the value as it mutates after each iteration.

Code Syntax

List<Task> tasks = new List<Task>();
string[] urls = Enumerable.Range(1, 10).Select(x => "Url-" + x.ToString()).ToArray();
foreach(var url in urls)
{
	tasks.Add(Task.Factory.StartNew(() => Console.WriteLine($"Data: {url}")));
}
Task.WaitAll(tasks.ToArray());
/*
Result - The order may vary 
Data: Url-2  
Data: Url-1  
Data: Url-5  
Data: Url-3  
Data: Url-8  
Data: Url-9  
Data: Url-10  
Data: Url-6  
Data: Url-7  
Data: Url-4
*/

Accessing For Loop Variables

However in for loop it only captures the final value, not the value as it mutates after each iteration.

Code Syntax

Task[] taskArray = new Task[10];
for(int i = 0; i < 10; i++) 
{
	taskArray[i] = Task.Factory.StartNew(() => Console.WriteLine($"Data: {i}"));
}
Task.WaitAll(taskArray);
/*
Result
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10  
Data: 10
*/

Pass Custom Data

You can pass custom data to the state parameter of Task.Factory.StartNewmethod.

class CustomData
{
   public int Index;
   public int ThreadId;
}
Task[] taskArray = new Task[10];
for(int i = 0; i < 10; i++) 
{
	 taskArray[i] = Task.Factory.StartNew((Object obj) => {
			var data = obj as CustomData;
		 	data.ThreadId = Thread.CurrentThread.ManagedThreadId;
	 	}, new CustomData { Index = i});
}
Task.WaitAll(taskArray);

Retrieve Data through AsyncState

foreach (var task in taskArray) 
{
	var data = task.AsyncState as CustomData;
	Console.WriteLine($"ThreadId {data.ThreadId} Index: {data.Index}");
}

Example