我很难过。在异步方法中,我有一些初始保护语句,如果满足特定条件则抛出异常。
其中一项如下:
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
这应该确保_transactionPages
字典中有页面,如果没有,则抛出。
这是我运行它时发生的事情(发布和调试版本,附带调试器):
因此字典中的页数是3。
因此,正如预期的那样,将3比0的if语句评估为false。
然而,当进一步迈进时:
它进入分支,好像if语句被评估为true,并抛出异常。
我在这里缺少什么?
更新
当我这样做时:
private static readonly object _globalLock = new object();
public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
lock (_globalLock)
{
if (IsCompleted)
throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
}
if语句不分支以抛出异常。调试和发布版本都是这种情况。是什么搞砸了调用堆栈?另外,如果不是锁定,而是在System.Threading.Thread.MemoryBarrier();
语句之后添加if
,它将不会进入分支。
更新2
这个谜团变得更大了。这几乎就像使用了c ++范围规则:D下面的代码(在调试版本中)将显示预期的行为:不进入分支而不抛出。在发布版本中,它将进入分支并像以前一样抛出。
private static readonly object _globalLock = new object();
public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
//lock (_globalLock)
{
if (IsCompleted)
throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
}
如果我评论&#34;范围大括号&#34;它将进入分支并抛出异常(如在我的原始图像中)。
FINAL?更新
那太糟糕了。我对不相关的代码区域做了一些更改,现在我不再能够重现这个问题了。
答案 0 :(得分:2)
我只找到过有效的方法。使用跟踪(希望是正确的东西,也许是log4net)。确保在每一行输出时间戳和threadId。 (还支持在需要的时候每次调用跟踪库的输出同步,而不必一直打开)
真的是这样的。
注意:只需写入文件或标准输出就可以获得第一个红色,但如果您开始使用它,请获取一个库。