如果语句的计算结果为false,但仍然分支,就好像它是真的一样

时间:2013-11-26 17:48:54

标签: c# debugging exception exception-handling

我很难过。在异步方法中,我有一些初始保护语句,如果满足特定条件则抛出异常。

其中一项如下:

var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
    throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));

这应该确保_transactionPages字典中有页面,如果没有,则抛出。

这是我运行它时发生的事情(发布和调试版本,附带调试器):

Number of pages is 3

因此字典中的页数是3。

if statement evaluates to false

因此,正如预期的那样,将3比0的if语句评估为false。

然而,当进一步迈进时:

Steps into the branch

它进入分支,好像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?更新

那太糟糕了。我对不相关的代码区域做了一些更改,现在我不再能够重现这个问题了。

1 个答案:

答案 0 :(得分:2)

哇,异步调试。

我只找到过有效的方法。使用跟踪(希望是正确的东西,也许是log4net)。确保在每一行输出时间戳和threadId。 (还支持在需要的时候每次调用跟踪库的输出同步,而不必一直打开)

真的是这样的。

注意:只需写入文件或标准输出就可以获得第一个红色,但如果您开始使用它,请获取一个库。