C# 异步lambda中引发的异常不是';Don’不要陷入代码中

C# 异步lambda中引发的异常不是';Don’不要陷入代码中,c#,asynchronous,lambda,C#,Asynchronous,Lambda,我看到过类似的问题(例如),但我仍然不确定为什么我的代码会这样运行。 我正在编写一些单元测试,用异步函数执行一些特定于线程的工作,但问题是没有捕获抛出的异常。这里有一个简单的例子来说明我的意思: static void Main(string[] args) { ExecuteWillCatch(async () => { await MyTaskFunction(); throw new Ex

我看到过类似的问题(例如),但我仍然不确定为什么我的代码会这样运行。 我正在编写一些单元测试,用异步函数执行一些特定于线程的工作,但问题是没有捕获抛出的异常。这里有一个简单的例子来说明我的意思:

    static void Main(string[] args)
    {
        ExecuteWillCatch(async () =>
        {
            await MyTaskFunction();
            throw new Exception("I throw an exception");
        });
    }

    static void MyAction()
    {
        MyTaskFunction();
        throw new Exception("I throw an exception!");
    }

    static async Task MyTaskFunction()
    {
        
    } 
    static void ExecuteWillCatch(Action action)
    {
        var op = new ThreadStart(() =>
        {
            try
            {
                action.Invoke();
            }
            catch (Exception e)
            {
                Console.WriteLine("I caught the exception");
            }

        });
        var thread = new Thread(op);
        thread.Start();
        thread.Join();
    }
如果我在测试中使用
async
lambda,那么发生的情况是在预期目标上抛出异常,然后在mscorlib中重试,然后在ExecuteWillCatch中的try-catch块中捕获not。如果我将async/wait替换为justwaiting,那么一切都将通过。这是一个我可以使用的变通方法,但我希望理想地测试代码,因为它将被使用(使用async/await)。 我还尝试将try-catch块放在主函数中,并围绕线程调用,认为可能会将异常抛出回该线程,但事实并非如此


有人能提出这样做的方法吗,或者解释为什么它不起作用吗?

我知道这个理论,不知道在你的情况下会发生什么。为了防止蓝屏,微软在调用main来处理任何未处理的异常之前,已经设置了一个默认的异常处理程序,作为托管代码的一部分。然后,在每次从方法返回时,都会有一个异常处理程序,即1)方法的异常处理程序2)方法内部的任何异常处理程序3)父级中的异常处理程序。所以,当异常发生时,异常会一直向上运行到执行堆栈,直到找到异常处理程序为止。我经常看到异常发生在异常处理程序的错误位置。看到许多现有的重复项。这里的基本问题是,根据设计,异步方法的语义是,此类方法中抛出的异常只能通过表示方法执行的
任务
来观察。
async void
方法没有这样的
任务
,但应用了相同的基本规则,使得异常完全不可观察。不要使用
async void
。使它<代码>异步任务< /代码>(即将参数从<代码>动作动作< /代码>改为<代码> FUNC动作< /代码>),然后>代码>等待<代码>调用。这可能有助于考虑非同步场景,即,如果<代码> MytaskFo函()/<代码>没有同步执行会发生什么。然后,在等待
MyTaskFunction()
后在继续中引发的异常可能不会发生在try/catch所在的同一线程中。如果不通过
wait
观察异常,该处理程序将不可能捕获异常。因此,规则是,如果没有
Wait
,异常总是不可观察的(好吧,您可以对返回的任务调用
Wait()
,但如果在这样的异步方法上阻塞,那将是愚蠢的)。另请参见(实际问题中只能列出五个重复项)