TPL Dataflow块中抛出的异常方法名称总是MoveNext()

时间:2015-07-12 13:01:44

标签: c# exception methods async-await task-parallel-library

我正在尝试在下面的示例中获取异常堆栈跟踪的大多数内部方法名称。由于未知原因,我总是得到MoveNext方法名称,而不是真实姓名。我该如何解决?

var st = new StackTrace(ex, true);
var frame = st.GetFrames()?.First(y => y.GetFileName() != null);
var method = frame.GetMethod().ToString(); // result: Void MoveNext()
var method2 = frame.Name; // result: MoveNext

更新

TPL Dataflow Block的委托中抛出异常时会发生这种情况:

private async Task Parse(ListItem item)
{
    await Task.Delay(1);
    throw new Exception("Error");
}

// ...

var parseBlock = new ActionBlock<ListItem>(
                    async x => { await Parse(x).ConfigureAwait(false); });

我从任何具有任何委托的区块获得MoveNext。堆栈跟踪:

at RP.Core.ListsPipeline.<Parse>d__21.MoveNext() in Class.cs:line 179
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Class.<<Start>b__18_0>d.MoveNext() in Class.cs:line 81

我想获得Parse方法名称(StackTrace的第一个字符串)。

2 个答案:

答案 0 :(得分:4)

此:

private async Task Parse(ListItem item)
{
    await Task.Delay(1);
    throw new Exception("Error");
}

获取翻译成:

private Task Parse()
{
    Program.<Parse>d__0 <Parse>d__;
    <Parse>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
    <Parse>d__.<>1__state = -1;
    AsyncTaskMethodBuilder <>t__builder = <Parse>d__.<>t__builder;
    <>t__builder.Start<Program.<Parse>d__0>(ref <Parse>d__);
    return <Parse>d__.<>t__builder.Task;
}

您的方法的实际调用是在编译器创建的状态机的MoveNext()方法内。这实际上意味着不会在Parse()内调用代码。这就是为什么您将MoveNext视为方法名称的原因,这就是无法Parse作为方法名称的原因。

答案 1 :(得分:0)

要解决this答案中解释的问题,请从Regex的异常堆栈跟踪中获取名称:

new Regex(@"\<(.*?)\>").Match(myException.StackTrace).ToString().Trim('>','<');

代替

myException.TargetSite.Name.ToString()