Подтвердить что ты не робот

Если выражение принимает значение false, но все равно веткится, как если бы оно было истинным

Я совершенно тупой. В async-методе у меня есть несколько начальных инструкций-хранителей, которые генерируют исключения, если выполняются особые условия.

Одно из них следующее:

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

И так, как и ожидалось, оператор if, сравнивающий 3 к 0, оценивает значение false.

Но тогда, когда шаг дальше:

Steps into the branch

Он вступает в ветвь, как если бы оператор if оценивался как true и генерировал исключение.

Что мне здесь не хватает?

UPDATE

Когда я это сделаю:

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

Тайна становится немного больше. Это почти так, как если бы использовались правила С++: 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));
    }

Если я прокомментирую "скобки скобок", он войдет в ветвь и выбросит исключение (как в моих исходных изображениях).

FINAL? UPDATE

Хорошо, что отстой. Я сделал несколько изменений в не связанных между собой областях кода, и теперь я больше не могу воспроизвести проблему.

4b9b3361

Ответ 1

Вау, асинхронная отладка.

Я только нашел один способ сделать это эффективно. Используйте трассировку (надеюсь, что-то приличное, может быть, log4net). Удостоверьтесь, что выводите метку времени и threadId на каждую строку. (также поддерживает синхронизацию вывода на вызов для трассировки библиотеки, когда она вам нужна, которая не должна быть постоянно)

Что это действительно так.

Примечание. Просто запись в файл или stdout работает для первого румянца, но если вы начнете использовать его больше, получите библиотеку.