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

Я хочу вернуть середину Func используемого блока. Должен ли я беспокоиться об утилизации до того, как пользователь запустит результат 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 зависит от пользователя этой службы.

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

Когда функция будет возвращена, транзакция будет удалена, а задача внутри функции уже будет выполняться. Вероятно, это не то, что вы хотите, судя по именам ваших методов? Вам нужно более точно указать, чего вы пытаетесь достичь.

Mo B. 20.12.2020 08:05

Я хочу отложить удаление до тех пор, пока пользователь не решит выполнить функцию результата.

FarhadGh 20.12.2020 08:09

Не могли бы вы привести пример того, как вы собираетесь использовать метод BeginTransaction?

Theodor Zoulias 20.12.2020 10:50

Я хотел достичь этих целей: 1. Никто не может совершить транзакцию дважды (поэтому я скрыл CommitTransaction) 2. Не заставляйте пользователя использовать блок с помощью (или использование одной строки) 3. Пользователь может делать что угодно с dbContext и несколькими saveChanges до совершение транзакции __ Также использование по умолчанию для моего случая находится в промежуточном программном обеспечении, до и после «ожидания следующего (контекста);»

FarhadGh 20.12.2020 14:48

Но я не мог достичь этих целей. Я вернул Транзакцию из сервиса, к сожалению.

FarhadGh 20.12.2020 14:54

Я не думаю, что предоставление пользователю возвращаемых значений Func<Task> имеет смысл или удобство. Если вы не хотите, чтобы они совершали транзакцию дважды, вы можете дать им Transaction фасад с CommitTransaction методом, который вызывает реальный базовый Transaction.CommitTransaction не более одного раза.

Theodor Zoulias 21.12.2020 04:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
200
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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();
}

или

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

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

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

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

FarhadGh 20.12.2020 08:21

@FarhadGh Обновил ответ.

user4182984 20.12.2020 08:36

Другие вопросы по теме