skip to Main Content

I have two code section in both of them I’m trying to use Func<Task>. Can anyone point out the difference between below two code sections. Which approach should I follow.

static void Main(string[] args)
{
    Func<Task<int>> getter = async () => await Get();

    int x = getter().Result;

    Console.WriteLine("hello : " + x);
}
        
static async Task<int> Get()
{
     await Task.Delay(1000);
     return 1;
}

static void Main(string[] args)
{
     Func<Task<int>> getter = () => Get();

     int x = getter().Result;

     Console.WriteLine("hello : " + x);
}
        
static async Task<int> Get()
{
      await Task.Delay(1000);
      return 1;
}

2

Answers


  1. For a trivial case like this both examples will do more or less the same thing.

    As a rule of thumb you should return the task directly without awaiting where you can. I.e. in cases where you call a single method that returns a task and do not do any processing of the result. But this is mostly for code style reasons, i.e. avoiding unnecessary keywords that might confuse a reader. So example 2 would be preferred.

    Ofc. In your specific example you should probably not use async at all, and prefer Thread.Sleep. In a UI program you should avoid using .Result, since it will block the UI thread, and increases the risk of deadlocks.

    Login or Signup to reply.
  2. The difference is a stacktrace in case of errors. If you modify the code a bit as following, you would see how results differ.

    internal class Example1
    {
        public static void Main(string[] args)
        {
            Func<Task<int>> getter = async () => await Get();
    
            int x = getter().Result;
    
            Console.WriteLine("hello : " + x);
        }
    
        static async Task<int> Get()
        {
            throw new Exception("test");
            await Task.Delay(1000);
            return 1;
        }
    }
    
    internal class Example2
    {
        public static void Main(string[] args)
        {
            Func<Task<int>> getter = () => Get();
    
            int x = getter().Result;
    
            Console.WriteLine("hello : " + x);
        }
    
        static async Task<int> Get()
        {
            throw new Exception("test");
            await Task.Delay(1000);
            return 1;
        }
    }
    

    When Example1 throws the exception, you see a stacktrace as following. Looking at the stacktrace, you know that the Get() method was called from the anonymous method.

    This exception was originally thrown at this call stack:
        StackOverflow.CSharp.Example1.Get() in Example.cs
        StackOverflow.CSharp.Example1.Main.AnonymousMethod__0_0() in Example.cs
    

    However, when Example2 throws the exception, the stacktrace is reduced and does not show where Get() was called from. It could be hard to trace a potential problem.

    This exception was originally thrown at this call stack:
        StackOverflow.CSharp.Example2.Get() in Example.cs
    

    In our projects, we prefer the first approach with async/await.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search