Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在异步方法中捕获了之后活动的异常_C#_Async Await_Clr - Fatal编程技术网

C# 在异步方法中捕获了之后活动的异常

C# 在异步方法中捕获了之后活动的异常,c#,async-await,clr,C#,Async Await,Clr,现在我知道首先使用Marshal.GetExceptionCode()是一种黑客行为,但问题不在于此(Visual Studio调试器还检测到活动异常) 输出 TestAsync.Before: 0 HandleExceptionAsync.Try: 0 Exception thrown: 'System.InvalidOperationException' in Interactive.dll Exception thrown: 'System.InvalidOperationExceptio

现在我知道首先使用
Marshal.GetExceptionCode()
是一种黑客行为,但问题不在于此(Visual Studio调试器还检测到活动异常)

输出

TestAsync.Before: 0
HandleExceptionAsync.Try: 0
Exception thrown: 'System.InvalidOperationException' in Interactive.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.ni.dll
HandleExceptionAsync.Catch: -532462766
HandleExceptionAsync.AfterCatch: -532462766
TestAsync.After: -532462766
The thread 9292 has exited with code 0 (0x0).
异常在整个等待链中保持活动状态,即使它已被捕获。 我检查了生成的代码,但它没有给出发生这种情况的线索,相关部分(为
HandleExceptionAsync
状态机生成的
MoveNext
):

void IAsyncStateMachine.MoveNext()
{
int num1=此状态。\u003C\u003E1\uuuu;
尝试
{
如果(num1==0)
;
尝试
{
任务等待者;
int num2;
如果(num1!=0)
{
Log(“HandleExceptionAsync.Try”);
waiter=Program.ThrowAsync().getwaiter();
如果(!waiter.IsCompleted)
{
这是。\u003C\u003E1\uuuu state=num2=0;
这。\u003C\u003Eu\uuuu 1=等待者;
程序。\u003CHandleExceptionAsync\u003Ed\uuu1状态机=此;
此。\u003C\u003Et\uuuu builder.AwaitUnsafeOnCompleted(ref WAITER,ref stateMachine);
返回;
}
}
其他的
{
等待者=此。\u003C\u003Eu\u1;
这是。\u003C\u003Eu__1=new TaskAwaiter();
这是。\u003C\u003E1\uuuu state=num2=-1;
}
GetResult();
等待者=新任务等待者();
}
捕获(无效操作异常ex)
{
Log(“HandleExceptionAsync.Catch”);
}
Log(“HandleExceptionAsync.AfterCatch”);
}
捕获(例外情况除外)
{
此。\u003C\u003E1\uuuu状态=-2;
这是.\u003C\u003Et\uuuu builder.SetException(ex);
返回;
}
此。\u003C\u003E1\uuuu状态=-2;
这是。\u003C\u003Et\uuuu builder.SetResult();
}
我也不认为这与同步上下文有关(在本例中,这是一个控制台应用程序,因此在池中安排了延续),我最好的猜测是发生了一些调用堆栈操作,但我找不到任何关于这方面的好信息

如果有人能解释为什么会发生这种情况,并提供文档链接,解释如何在CLR/编译器中实现这一点,我将不胜感激

UPD1:添加了VS调试器的屏幕截图,显示了一个异步的活动异常,但同步时没有显示任何内容

异步

同步

如果在
日志(“HandleExceptionSync.AfterCatch”)上放置断点,调用堆栈解释了技巧:

ConsoleApp1.exe!ConsoleApp1.Program.Log(string step) Line 107   C#
ConsoleApp1.exe!ConsoleApp1.Program.HandleExceptionAsync() Line 95  C#
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)  Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()    Unknown
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)    Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()  Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishStageTwo()   Unknown
mscorlib.dll!System.Threading.Tasks.Task.Finish(bool bUserDelegateExecuted) Unknown
mscorlib.dll!System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>.TrySetException(object exceptionObject) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>.SetException(System.Exception exception) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception exception)    Unknown
ConsoleApp1.exe!ConsoleApp1.Program.ThrowAsync() Line 101   C#
... (continues until the timer of Task.Delay)
简单地说,由于
wait
关键字,您的
HandleExceptionAsync
方法如下所示:

void HandleExceptionAsync1()
{
    Log("HandleExceptionAsync.Try");
}

void HandleExceptionAsync2()
{
    Log("HandleExceptionAsync.AfterCatch");
}
当然,这要比那复杂得多。事实上,该方法并没有被切碎,只是简单地转换成一个状态机。然而,对于这个演示,这是相当合理的

HandleExceptionAsync2
需要在
ThrowAsync
之后执行。因此,
handleExceptionSync2
将作为一个延续链接。比如:

ThrowAsync().ContinueWith(HandleExceptionAsync2);
(同样,这比那要复杂得多。我只是简单解释一下)

“问题”是,当运行时完成ThrowAsync返回的任务时:

System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>.TrySetException(object exceptionObject)
System.Threading.Tasks.Task.TrySetException(对象异常对象)

延续实际上是内联的,并在同一个调用堆栈中执行(参见上面的框架)。出于性能原因,这是TPL经常进行的优化。因此,当调用
Log(“HandleExceptionAsync.AfterCatch”)
您实际上仍然处于ThrowAsync的catch块中,因此您看到的行为。

GetExceptionCode
已经发生。如果您有一个在捕获后导致“活动”异常的场景,请发布该问题的复制。@StephenCleary此特定代码在VS调试器中将异常显示为活动($exception variable)。这个复制不是为你准备的吗?对我来说,“活动”意味着它被抛出(或者——在扩展使用中——被捕获)。你看到过这样的行为吗,还是仅仅是
$exception
调试器变量?@StephenCleary只是变量谢谢,这是一个很好的解释,整个事情现在对我来说非常有意义,我查看生成的状态机有一段时间了,只是没有想到会从编译器捕获生成的内部执行延续!
void HandleExceptionAsync1()
{
    Log("HandleExceptionAsync.Try");
}

void HandleExceptionAsync2()
{
    Log("HandleExceptionAsync.AfterCatch");
}
ThrowAsync().ContinueWith(HandleExceptionAsync2);
System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>.TrySetException(object exceptionObject)