0
    public class Program
    {   
        public static T TakeFunc<T>(Func<T> func){
            
            try{
                var x = func();
                Console.WriteLine("Success");
                return x;
            }
            catch(Exception ex){
                Console.WriteLine("ex caught");
                return default(T);
            }
            finally{
                Console.WriteLine("finally");
            }
            
        }
        
        public static void Main(string[] args)
        {
            TakeFunc(async () => await test());
        }
        
        private async static Task<List<string>> test(){
           await Task.Delay(1000);
           List<string> a = null;
           a.Add("sdff");
           return a;
        }
    }

The output of this is:

Success
finally

Why isn't the ex caught even though the test method is under an await? I've read that await usually catches the error. Does this have something to do with the delegate being asynchronous?

Giridhar
  • 155
  • 1
  • 8
  • 2
    You need that to be a `Func>`, and you need to `await x` (which means that `TakeFunc` needs to be `async Task`) – canton7 Jun 03 '21 at 13:21
  • Or change `public static async Task Main(string[] args)` and `await TakeFunc(async () => await test());` as it is. Otherwise, you have to catch it in `test()`. – Jimi Jun 03 '21 at 13:34
  • @Jimi That change would not have the `await` inside of the `try` so it would be the same problem. – juharr Jun 03 '21 at 13:45
  • @juharr Yes, it's missing an *explicit* piece before *otherwise*: "and catch it in Main" (where you await, that is). The starting `Or` was proposing an alternative to the comment above. – Jimi Jun 03 '21 at 13:47
  • @juharr ...but without awaiting in Main, an async `TakeFunc()` is just fire-and-forget, so the OP might as well write `TakeFunc(()=> test());` – Jimi Jun 03 '21 at 14:13

2 Answers2

0

You are awaiting yes, however you are not awaiting the call to the delegate, which means execution goes right through the call, this is why you end up with Success and Finally. So the answer is we need to await for func() to run and have the opportunity to throw an exception. So making Main async, TakeFunc async that accepts Func Task T should allow you to put in proper await's here.

Here is the code..

public class Program
{
    public static async Task<T> TakeFunc<T>(Func<Task<T>> func)
    {

        try
        {
            var x = await func();
            Console.WriteLine("Success");
            return x;
        }
        catch (Exception ex)
        {
            Console.WriteLine("ex caught");
            return default(T);
        }
        finally
        {
            Console.WriteLine("finally");
        }

    }

    public static async Task Main(string[] args)
    {
        await TakeFunc(async () => await test());
    }

    private static async Task<List<string>> test()
    {
        await Task.Delay(1000);
        List<string> a = null;
        a.Add("sdff");
        return a;
    }
}
Zach Hutchins
  • 801
  • 1
  • 12
  • 16
0

The await Task.Delay suspends the evaluation of test() and the control returns to the caller TakeFunc, and hence continues to write Success and finally.

Only after the 1000ms delay it continues to run test().

So either move the try/catch inside test() or add async/await all the way up until Main.

Udi Y
  • 258
  • 3
  • 12
  • *"and the control returns to the caller TakeFunc*", it actually returns to `Main`. "*Only after the 1000ms delay it continues to run test().*", it actually runs the remaining non async part after 1000ms. – CodingYoshi Jun 03 '21 at 19:16