Вернуть Func ‹Task› в середине блока Using

Я хочу вернуть Func в середине блока using. Стоит ли беспокоиться об утилизации до того, как пользователь запустит результат Func?

Пример кода:

private IDbContextTransaction _transaction;

public Func<Task> BeginTransaction()
{
    Task lockDispose = CommitTransaction();
    using (_transaction = _dbContext.Database.BeginTransaction())
    {
        return async() =>
        {
            await lockDispose;
        };
        Task.WaitAll(lockDispose); //This code is unreachable.
    }
}

private async Task CommitTransaction()
{
    _transaction.Commit();
    await Task.CompletedTask;
}

Обратите внимание, что время выполнения результата Func зависит от пользователя этой службы.

Я проверил этот вопрос, и это не мой ответ.


person FarhadGh    schedule 20.12.2020    source источник
comment
Когда функция возвращается, транзакция будет удалена, в то время как задача внутри функции уже будет выполняться. Вероятно, это не то, что вам нужно, судя по названиям ваших методов? Вам нужно более точно указать, чего вы пытаетесь достичь.   -  person Mo B.    schedule 20.12.2020
comment
Я хочу отложить удаление, пока пользователь не решит выполнить функцию результата   -  person FarhadGh    schedule 20.12.2020
comment
Не могли бы вы привести пример того, как вы собираетесь использовать метод BeginTransaction?   -  person Theodor Zoulias    schedule 20.12.2020
comment
Я хотел достичь следующих целей: 1. Никто не может зафиксировать транзакцию дважды (поэтому я скрыл CommitTransaction) 2. Не заставляйте пользователя использовать блок (или использовать одну строку) 3. Пользователь может делать что угодно с dbContext и несколькими saveChanges раньше совершение транзакции __ Также по умолчанию в моем случае используется промежуточное ПО до и после 'await next (context);'   -  person FarhadGh    schedule 20.12.2020
comment
Но я не смог достичь этих целей. К сожалению, я вернул Транзакцию из сервиса.   -  person FarhadGh    schedule 20.12.2020
comment
Я не думаю, что предоставление пользователю Func<Task> возвращаемых значений имеет смысл или удобно. Если вы не хотите, чтобы они фиксировали транзакцию дважды, вы можете дать им Transaction фасад с CommitTransaction методом, который вызывает реальный базовый Transaction.CommitTransaction не более одного раза.   -  person Theodor Zoulias    schedule 21.12.2020


Ответы (1)


Поскольку вы хотите, чтобы ваш пользователь мог работать с соединением между вызовами BeginTransaction и CommitTransaction, единственное, что вы можете сделать, - это переместить удаление за пределы этой области:

private IDbContextTransaction _transaction;

public Func<Task> BeginTransaction()
{
    _transaction = _dbContext.Database.BeginTransaction()
    return CommitTransaction;
}

private async Task CommitTransaction()
{
    _transaction.Commit();
    _transaction.Dispose();
    await Task.CompletedTask;
}

// I advice you implement IDisposable fully, but 
// this will do for the sake of demonstration
public void Dispose()
{
    _transaction?.Dispose();
}

А затем где-то снаружи вам нужно будет сделать что-то вроде:

using (var obj = TheWayYouInitializeYourObject())
{
    var commit = obj.BeginTransaction();
    // DO WORK
    await commit();
}

or

try
{
    var commit = obj.BeginTransaction();
    // DO WORK
    await commit();
}
finally
{
    obj.Dispose();
}

По сути, ваш using не может перекрыть промежуток, в котором работает ваш пользователь, поэтому им придется делать это самостоятельно.

Как правило, неплохо делать предметы, которые должны работать с одноразовыми предметами, также одноразовыми.

person Heagon    schedule 20.12.2020
comment
Сомневаюсь, что после вызова BeginTransaction () транзакция начнется. И после этого пользователь должен работать с dbContext. Я протестирую ваше решение и приду снова, чтобы обновить этот комментарий. - person FarhadGh; 20.12.2020
comment
@FarhadGh Обновил ответ. - person Heagon; 20.12.2020