Как создать обёртку с try/catch для методов С#?

Рейтинг: 0Ответов: 1Опубликовано: 10.04.2023

У меня есть множество методов в разных репозиториях с таким кодом:

await using var transaction = await context.Database.BeginTransactionAsync();
await transaction.CreateSavepointAsync("Transaction");
try
{
    // какая-то функциональность, например, обновление модели в базе или её создание
}
catch (Exception)
{
    await transaction.RollbackToSavepointAsync("Transaction");
    return default;
}

Эти try/catch занимают очень много места. Возможно ли как-то их вынести, чтобы они автоматически применялись к методу?

Пробовал сделать с атрибутом, но как я понял, атрибуты нужны для какой-то мета информации, а не для функциональности.

Ответы

▲ 1Принят

Допустим это так

async Task<T> SomeMethodAsync(SomeArgs args)
{
    await using var transaction = await context.Database.BeginTransactionAsync();
    await transaction.CreateSavepointAsync("Transaction");
    try
    {
        // ...
        return result;
    }
    catch (Exception)
    {
        await transaction.RollbackToSavepointAsync("Transaction");
        return default;
    }
}

Тогда можно сделать метод таким

async Task<T> SomeMethodAsync(SomeArgs args)
{
    // ...
    return result;
}

А обертку вот так

async Task<T> TransactionAsync(Func<SomeArgs, Task<T>> func, SomeArgs args)
{
    await using var transaction = await context.Database.BeginTransactionAsync();
    await transaction.CreateSavepointAsync("Transaction");
    try
    {
        return await func(args);
    }
    catch (Exception)
    {
        await transaction.RollbackToSavepointAsync("Transaction");
        return default;
    }
}

А вызывать так

var result = await TransactionAsync(SomeMethodAsync, args);

Можно сделать эту обертку обобщенной, чтобы не зависеть от конкретных типов.