Почему - как-операции обрабатываются после выбытия?


Я пытаюсь работать с некоторыми окружающими областями транзакций (Спасибо, entity-framework), чего я на самом деле не делал раньше, и я вижу некоторые ... странное поведение, которое я пытаюсь понять.

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

Для этого класс,

class WtfTransactionScope : IDisposable, IEnlistmentNotification
{
    public WtfTransactionScope()
    {
        if(Transaction.Current == null)
            return;
        Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
    }
    void IEnlistmentNotification.Commit(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("Committed");
    }

    void IEnlistmentNotification.InDoubt(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("InDoubt");
    }

    void IEnlistmentNotification.Prepare(
        PreparingEnlistment preparingEnlistment)
    {
        Console.WriteLine("Prepare called");
        preparingEnlistment.Prepared();
        Console.WriteLine("Prepare completed");
    }

    void IEnlistmentNotification.Rollback(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("Rolled back");
    }

    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }
}

При использовании, как показано здесь

using(var scope = new TransactionScope())
using(new WtfTransactionScope())
{
    scope.Complete();
}

Вывод консоли демонстрирует wtf-ness:

Утилизирован
Подготовка называется
Совершено
Подготовка завершена

ВУТ.

Я получаю распоряжение до завершения сделки. Этот... своего рода сводит на нет преимущества зависания с объемом сделки. Я надеялся, что меня проинформируют, как только сделка завершится успешно (или нет), чтобы я мог сделать некоторые работа. Я был к сожалению предполагая, что это произойдет после scope.Complete() и до того, как я буду удален, когда мы выйдем из области using. По-видимому, это не так.

Конечно, я мог бы взломать его. Но у меня есть и другие проблемы, которые существенно мешают мне сделать это. Мне придется отказаться и сделать что-то еще в этом случае.

Я делаю здесь что-то не так? Или это ожидаемое поведение? Можно ли что-то сделать по-другому, чтобы предотвратить это от происходящего??

1 9

1 ответ:

Это причиненная самому себе боль. Вы нарушаете очень простое правило для IDisposable, объект должен быть удален только тогда, когда он больше нигде не используется. Это является используется, когда ваш оператор using вызывает Dispose (), вы передали ссылку на ваш объект в конструкторе WtfTransactionScope. Вы не можете избавиться от него, пока он не будет завершен, что обязательно означает, что вы должны избавиться от него после того, как оператор using для TransactionScope завершится и транзакция получил обязательство/откат.

Я позволю вам беспокоиться о том, чтобы сделать его красивым, но очевидный способ:

using(var wtf = new WtfTransactionScope())
using(var scope = new TransactionScope())
{
    wtf.Initialize();
    scope.Complete();
}

Prepare completed - это всего лишь бесполезный отладочный оператор. Просто удалите его.