Я совершенно тупой. В async-методе у меня есть несколько начальных инструкций-хранителей, которые генерируют исключения, если выполняются особые условия.
Одно из них следующее:
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
Предполагается обеспечить наличие страниц в словаре _transactionPages
и выбросить, если их нет.
Это то, что происходит, когда я запускаю его (сборка отладки и отладки, прикрепленный отладчик):
Таким образом, количество страниц в словаре равно 3.
И так, как и ожидалось, оператор if, сравнивающий 3 к 0, оценивает значение false.
Но тогда, когда шаг дальше:
Он вступает в ветвь, как если бы оператор 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
Хорошо, что отстой. Я сделал несколько изменений в не связанных между собой областях кода, и теперь я больше не могу воспроизвести проблему.