.net断言显示条件失败

时间:2011-05-18 01:11:12

标签: .net visual-studio-2010 f# assert

好吧,我习惯了旧的C断言,当他们失败时,他们输出他们失败的条件,以及它所在的线路。 (与预处理器一起使用)。

现在我用F#编程(.net语言),代码充满了断言。 (尝试防御性地编程)。我的资产显示了一个带调用堆栈的弹出窗口。根据{{​​3}},也可以传递断言字符串,以便在失败时显示。所以我可以通过我的条件的字符串副本。例如:

assert (x=true, "x=true")

但这违反了复制(避免)委托人。

如果我后来决定改变我想要断言的东西。 (也许我意识到当我应该断言它是真的时我声称某些东西是假的)然后我必须在两个地方更改代码,否则消息将与我实际检查的内容不匹配。如果我忘了事情可能会让人感到困惑。

这通常如何处理?

3 个答案:

答案 0 :(得分:5)

回应Tomas所说的,你可以使用引用来避免重复。但是,而不是显然生成C#源代码的ToLinqExpression -> ToString,您可以使用我的库Unquote来生成F#源代码字符串。将此与适用于生产代码的实现相结合(即定义Assert内联非DEBUG编译符号分支,仅发出no-op ()意味着使用Assert将在启用了优化的非DEBUG版本中完全删除):

let inline Assert (q:Expr<bool>) =
    #if DEBUG
        System.Diagnostics.Debug.Assert(q.Eval(), q.Decompile())
    #else
        ()
    #endif

然后断言表达式Assert <@ (22 + 2) / 2 = ("assert" |> String.length) @>默认生成以下弹出对话框(我认为你可以配置System.Diagnostics.Debug行为):

enter image description here

比较q.ToLinqExpression().ToString()生成(((22 + 2) / 2) == op_PipeRight("assert", ToFSharpFunc(str => Length(str))))的位置。

事实上,Unquote是专门为生成有用的单元测试断言失败消息而设计的,并且可以很容易地适应调试断言,产生逐步失败消息:

let inline Assert (q:Expr<bool>) =
    #if DEBUG
        System.Diagnostics.Debug.Assert(q.Eval(), q.ReduceFully() |> List.map (fun q -> q.Decompile()) |> String.concat System.Environment.NewLine)
    #else
        ()
    #endif

enter image description here

答案 1 :(得分:4)

无论您询问什么断言,都无法自动获取失败条件的文本表示。最好的选择是通过使用带有消息的重载来显式提供信息:

Debug.Assert(a = 10, "A should be 10")

如果您不需要担心Assert的性能,那么您可以使用F#引用。它们代表编写的代码,可以进行评估(测试断言)并格式化为字符串:

#r @"C:\Programs\Development\PowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

/// Assert that tests whether a quoted condition is true and throws
/// an exception containing a string representation of the code
let Assert (q:Expr<bool>) = 
  if not(q.Eval()) then failwithf "Assertion failed: %O" (q.ToLinqExpression())

let test() = 
  let a = 10
  Assert <@ a = 11 @>

调用test函数会在下面给出消息。调用ToLinqExpression为您提供了一个LINQ Expression对象,它实现了比F#引用更好的ToString操作:

  

System.Exception:断言失败:(10 == 11)

答案 2 :(得分:2)

C与F#完全不同。 C代码必须留下足够的面包屑,以使断言消息足够有意义,以帮助您找出断言失败的代码。

这在托管代码中不是问题。你得到一个堆栈跟踪,不需要字符串。