StackTrace,流畅通话的线路信息

本文关键字:线路 信息 StackTrace | 更新日期: 2023-09-27 18:24:39

给定以下流畅的API调用:

Foo()
    .Bar1(() => { ... })
    .Bar2(() => { ... })
    .Bar3();

我想确定代码文件和Bar1、Bar2和Bar3行的行号,稍后向下(嗯…向上)它们的调用堆栈。。。

案例1:。。。在Bar1/Bar2/Bar3扩展方法中。

我当前的解决方案:我立即在这些方法中创建堆栈跟踪并查找信息。

打开的问题:线路信息属于Foo()线路,而不是Bar#(...)线路:(

情况2:。。。稍后,在代码的其他地方,以防给定的委托在执行时抛出异常。

我当前的解决方案:我检查异常的堆栈跟踪并找到正确的行:)

特殊情况3:Bar3在方法内部定义委托,当这样的委托抛出异常时,我现在仍然想使用.Bar3()行。

我目前的解决方案:还不知道,委托是在其他地方创建的,我不能使用与情况2相同的方法。我唯一的机会是案例1中的信息,然而,该信息并不完全正确(行号错误)。

Q:您知道如何在这三种情况下确定正确的代码文件和行号吗?

注意:性能并不重要,因为它是测试框架的一部分。

StackTrace,流畅通话的线路信息

.NET 4.5包含调用方信息属性,这是一种更干净的方法:

using System.Runtime.CompilerServices;
...
public Foo Bar1(
    Action, 
    [CallerMemberName] string memberName = "",
    [CallerFilePath] string sourceFilePath = "",
    [CallerLineNumber] int sourceLineNumber = 0)
{
    ...
}

这里的最大好处是您不必在运行时做任何事情。参数是在编译时提供的,因此这对方法的性能没有影响。不幸的是,没有什么可以阻止用户代码绕过它,例如:

Foo().Bar1(() => { ... }, "not a real method", "not a real file", -123);

您的代码实际上是一行代码,因此信息本身并不是错误的。你需要拆分它:

var foo = Foo();
var bar1 = foo.Bar1(() => { ... });
var bar2 = bar1.Bar2(() => { ... });
var bar3 = bar2.Bar3();

这是我能想到的最简单、最快的"修复"。您也可以利用region来提高清晰度:

#if(DEBUG)
// When compiling in debug
var foo = Foo();
var bar1 = foo.Bar1(() => { ... });
var bar2 = bar1.Bar2(() => { ... });
var bar3 = bar2.Bar3();
// additional code might be needed, depending on the real code...
#else
// When compiling in Release
Foo()
    .Bar1(() => { ... })
    .Bar2(() => { ... })
    .Bar3();
#endif