我正在为一个软件构建工具,并希望能够在Debug.Assert
(或Trace.Assert
)调用中存在的源代码中保存布尔表达式。
例如,如果程序崩溃:
var x = -1;
Debug.Assert(x >= 0, "X must be non-negative", "some detail message");
我希望能够输出字符串"x >= 0"
以及消息和详细消息。
我已经考虑使用TraceListener
,但TraceListener#Fail(string)
和TraceListener#Fail(string, string)
只能捕获消息和详细消息字段(在开发人员不包含的情况下,让我没有简单的方法来报告出了什么问题。)
我认为可以创建堆栈跟踪并读取失败的特定行并报告(假设源代码可用),但这似乎相对脆弱。
谢谢你的时间!
答案 0 :(得分:2)
您可以使用表达式来完成粗略的事情:
public static class DebugEx
{
[Conditional("DEBUG")]
public static void Assert(Expression<Func<bool>> assertion, string message)
{
Debug.Assert(assertion.Compile()(), message, assertion.Body.ToString());
}
}
并像这样使用它:
var i = -1;
DebugEx.Assert(() => i > 0, "Message");
这有一些不利因素。首先,你必须使用lambda,这样会使语法复杂化一点。第二个是因为我们正在动态编译事物,所以性能受到了打击。由于这只会在调试模式下发生(因此是条件),因此在发布模式下不会出现性能损失。
最后,输出并不漂亮。它看起来像这样:
(value(WindowsFormsApplication1.Form1 +&lt;&gt; c__DisplayClass0).i&gt; 0)
你可以做很多事情。发生这种情况的原因是i
周围的封闭。这实际上是准确的,因为这是它被编译成的内容。
答案 1 :(得分:2)
当@vcsjones发布他的answer时,我已经开始输入答案了,所以我放弃了我的,但我看到它的某些部分仍然相关。主要是将lambda表达式格式化为可读的东西,所以我将把他的部分与我想要的答案合并。
它使用许多正则表达式来格式化断言表达式,因此在许多情况下它看起来很不错(即接近您输入的内容)。
对于@vcsjones中给出的示例,答案现在看起来像这样:
断言'(i> 0)'失败。
public static class DebugEx
{
private static readonly Dictionary<Regex, string> _replacements;
static DebugEx()
{
_replacements = new Dictionary<Regex,string>()
{
{new Regex("value\\([^)]*\\)\\."), string.Empty},
{new Regex("\\(\\)\\."), string.Empty},
{new Regex("\\(\\)\\ =>"), string.Empty},
{new Regex("Not"), "!"}
};
}
[Conditional("DEBUG")]
public static void Assert(Expression<Func<bool>> assertion, string message)
{
if (!assertion.Compile()())
Debug.Assert(false, message, FormatFailure(assertion));
}
private static string FormatFailure(Expression assertion)
{
return string.Format("Assertion '{0}' failed.", Normalize(assertion.ToString()));
}
private static string Normalize(string expression)
{
string result = expression;
foreach (var pattern in _replacements)
{
result = pattern.Key.Replace(result, pattern.Value);
}
return result.Trim();
}
}