I finally find out the answer Task.FromRexult
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult?view=net-5.0
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
I'm sorry that I did not explain my intention with more detail demo code at the first place.
Here is more near to my original intention demo code:
I'm am so sorry that I wasted your guys precious time in pervious posted.
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.VisualStudio.Threading;
namespace ns
{
using Queue = AsyncQueue<Object>;
public class Object
{
public string Message { get; set; } = string.Empty;
}
public class Program
{
//This is still a demo code. actually my code is in
//WPF Desktop App, something like this:
// button1.Click += button1_Click;
// private async void button1_Click()
// {
// var queue = new Queue();
// await Task.WhenAll(...);
// }
public static async Task Main()
{
var queue = new Queue();
await Task.WhenAll(ProducerAsync(queue), ConsumerAsync(queue));
}
static public async Task ProducerAsync(Queue queue)
{
int i = 0;
while (true)
{
await Task.Delay(1000);
queue.Enqueue(new Object() { Message = $"A message with index={i++}." });
}
}
static public async Task ConsumerAsync(Queue queue)
{
Object lastObject = null;
Random rd = new Random();
EntryPoint:
//allow some resources, for example TCP connection.
//
var timeout = Task.Delay(1000);
Task<Object> data;
if (lastObject != null)
{
Console.WriteLine("Put pending data into a task for later handling");
//I Think there is no need to call data.run()(or Task.Run(...))
//to put the lambda expr into a thread pool run asynchronously
//since What i want is that just put it into Task and for later
//await to receive the object from the task.
//a task obj should be Scheduling to start when you
//await it when it not started, is that right?
data = new Task<Object>(() => lastObject);
lastObject = null;
}
else
{
data = queue.DequeueAsync();
}
var tasks = new List<Task>() { timeout, data };
while (tasks.Count > 0)
{
var finished = await Task.WhenAny(tasks);
tasks.Remove(finished);
if (finished == timeout)
{
try
{
//Some operations that may throw exceptions,
//for example, TCP connection broken.
//here is -1, so it won't throw exception for now...
//let us focus at data code below.
if (rd.Next(0, 3) == -1)
throw new Exception("Exception in timeout.");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
if (data.IsCompleted)
{
lastObject = await data;
}
goto EntryPoint;
}
tasks.Add(timeout = Task.Delay(1000));
}
if (finished == data)
{
lastObject = await data;
try
{
//Another operations that may throw exceptions
//for example, TCP connection broken.
if (rd.Next(0, 4) == 0)
{
throw new Exception("Exception in data.");
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
goto EntryPoint;
}
Console.WriteLine($"{lastObject.Message} was handled successfully.");
//If everything go well.
lastObject = null;
tasks.Add(data = queue.DequeueAsync());
}
}
}
}
}
It finally stuck at
A message with index=0. was handled successfully.
A message with index=1. was handled successfully.
A message with index=2. was handled successfully.
A message with index=3. was handled successfully.
Exception in data.
Put pending data into a task for later handling
// Stucked.
I finally find out the answer Task.FromRexult
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult?view=net-5.0
I think you are looking for a pattern like below. Reference doc.
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
Console.WriteLine("Stuck at \"await task\" ...");
string str = await ExampleMethodAsync();
Console.WriteLine("return from await");
Console.WriteLine(str);
}
private static async Task<string> ExampleMethodAsync()
{
await Task.Delay(10);
return "Hello World";
}
}
Here is an example working with a method for int and a method for string.
Example 1
using System;
using System.Threading.Tasks;
namespace AsyncMain
{
class Program
{
public static async Task<int> Main(string[] args)
{
static Task<string> Simple() => Task.Run(async () =>
{
await Task.Delay(2000);
return $"{nameof(Simple)}";
});
Console.WriteLine(await Simple());
Console.ReadKey();
return 0;
}
}
}
Example 2
using System;
using System.Threading.Tasks;
namespace AsyncMain
{
class Program
{
public static async Task<int> Main(string[] args)
{
Console.Title = "async Task<int> Main";
int number1 = 5, number2 = 10;
Console.WriteLine($"Sum of {number1} and {number2} is: {await AdditionAsync(number1, number2)}");
Console.WriteLine(await Simple());
Console.WriteLine("Press any key to exist.");
Console.ReadKey();
return 0;
}
private static Task<int> AdditionAsync(int value1, int value2)
{
return Task.Run(() => SumIt(value1, value2));
int SumIt(int x, int y)
{
return x + y;
}
}
private static Task<string> Simple() => Task.Run(() => $"{nameof(Simple)}");
}
}
A working demo code below
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.VisualStudio.Threading;
namespace ns
{
using Queue = AsyncQueue<Object>;
public class Object
{
public string Message { get; set; } = string.Empty;
}
public class Program
{
//This is still a demo code. actually my code is in
//WPF Desktop App, something like this:
// button1.Click += button1_Click;
// private async void button1_Click()
// {
// var queue = new Queue();
// await Task.WhenAll(...);
// }
public static async Task Main()
{
var queue = new Queue();
await Task.WhenAll(ProducerAsync(queue), ConsumerAsync(queue));
}
static public async Task ProducerAsync(Queue queue)
{
int i = 0;
while (true)
{
await Task.Delay(1000);
queue.Enqueue(new Object() { Message = $"A message with index={i++}." });
}
}
static public async Task ConsumerAsync(Queue queue)
{
Object lastObject = null;
Random rd = new Random();
EntryPoint:
//allow some resources, for example TCP connection.
//
var cts = new CancellationTokenSource();
var timeout = Task.Delay(1000);
Task<Object> data=null;
if (lastObject != null)
{
//Console.WriteLine("Put pending data into a task for later handling");
data = Task.FromResult(lastObject);
}
else
{
data = queue.DequeueAsync(cts.Token);
}
var tasks = new List<Task>() { timeout, data };
while (tasks.Count > 0)
{
var finished = await Task.WhenAny(tasks);
tasks.Remove(finished);
if (finished == timeout)
{
try
{
//Some operations that may throw exceptions,
//for example, TCP connection broken.
//here is -1, so it won't throw exception for now...
//let us focus at data code below.
if (rd.Next(0, 2) == 0)
throw new Exception("Exception in timeout.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
cts.Cancel();
try
{
lastObject = await data;
}catch when (cts.IsCancellationRequested)
{
lastObject = null;
}
goto EntryPoint;
}
tasks.Add(timeout = Task.Delay(1000));
}
if (finished == data)
{
var ret = await data;
try
{
//Another operations that may throw exceptions
//for example, TCP connection broken.
if (rd.Next(0, 2) == 0)
{
throw new Exception("Exception in data.");
}
}
catch (Exception ex)
{
lastObject = ret;
Console.WriteLine(ex.Message);
goto EntryPoint;
}
Console.WriteLine($"{ret.Message} was handled successfully.");
//If everything go well.
lastObject = null;
tasks.Add(data = queue.DequeueAsync());
}
}
}
}
}