调试的求值顺序.在.net 4.5.2中断言(condition, interpolatedStringMessage)

本文关键字:断言 中断 condition interpolatedStringMessage 顺序 net 调试 | 更新日期: 2023-09-27 18:14:58

我偶然发现了c#/中一个奇怪的问题。Net 4.5.2这里…

我有一个!ContainsKey()检查在Debug.Assert()与一个插入字符串包含值,如果发现,像这样

var dict = new Dictionary<string, string>();
string invalidKey = "invalidKey";
try
{
    Debug.Assert((!dict.ContainsKey(invalidKey)), $"{nameof(dict)} contains the key {dict[invalidKey]}!");
}
catch (KeyNotFoundException)
{
    Console.WriteLine("AssertionString was interpolated before the check was performed!");
}

(仅在第一个版本中没有try-catch块)

我本以为永远不会遇到catch那里,也是情况,例如检查代码在。netfiddle(见https://dotnetfiddle.net/RyQooW),然而,在Visual Studio中,在。net 4.5.2下运行代码,我得到以下内容:

插入字符串在断言条件

之前求值

这绝对是字符串插值(而不是ContainsKey的问题),因为当我从消息中删除插值时,异常不会被抛出。

求值顺序不能保证吗?我认为如果断言为真,字符串不会被插入。

或者这只是一个错误在这个版本的。net运行时(可能是一个优化插入断言字符串早期使它们静态或什么?)

感谢您的任何输入,干杯!

调试的求值顺序.在.net 4.5.2中断言(condition, interpolatedStringMessage)

好了,对于每个被这个绊倒的人:

显然是不是一个bug,而实际上只是Debug.Assert是一个常规方法(不是一些特殊的内置助手,等等,参见Microsoft的参考源代码),因此任何字符串参数都必须在进入方法之前插入(因为有问题的对象可能在调用范围之外不可用)。
但是,由于条件和消息都是方法参数,并且条件的求值发生在方法的内部(并且而不是方法调用作为求值的结果),因此当然在进入方法并检查条件之前抛出上述KeyNotFoundException

唯一让Debug.Assert有点特别的是它有一个[System.Diagnostics.Conditional("DEBUG")]属性,因此在非调试构建中被剥离。

所以这实际上是完全可以理解和正确的行为(在任何 dot net版本中),尽管它是一种陷阱。