【问题标题】:StackTrace, line info of fluent callStackTrace,流畅调用的线路信息
【发布时间】:2013-07-23 06:24:39
【问题描述】:

鉴于以下流畅的 API 调用:

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

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

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

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

未解决的问题: 线路信息属于Foo() 线路,而不是Bar#(...)-线路:(

案例 2: ...稍后,在代码中完全位于其他位置的地方,以防给定的委托在执行时引发异常。

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

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

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

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

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

【问题讨论】:

  • 据我所知,这一行与一行代码有关。我敢猜测,Visual Studios 的调试器也会这样认为。我认为您必须将其拆分为 3 个单独的方法调用
  • 您可以在代表上设置断点,即使您必须先选择它然后设置断点。有点棘手,但它有效。

标签: c# stack-trace


【解决方案1】:

.NET 4.5 包含 Caller Information Attributes,这是一种更简洁的方式:

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);

【讨论】:

  • 我也为您的答案 +1,但是,尽管我的用户不会覆盖这些方法参数(自己动手......),但它确实让我的 API 变得“肮脏”。因此,也欢迎任何其他答案。
【解决方案2】:

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

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

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

#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

【讨论】:

  • 感谢您的回答,但是,这对我的 API 用户来说更糟糕 ;-)
猜你喜欢
  • 2010-09-28
  • 2010-10-11
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多