C# - Почему моя функция-обертка для обработки ошибок не перехватывает исключения? - PullRequest
0 голосов
/ 04 мая 2020

Я использую следующее для общего переноса функциональности:

public static class ErrorHandling
{
    public static void TryCatchErrors<TLogger>(ILogger<TLogger> logger, Action action, string? customMsg = null) => TryCatchErrors<TLogger, object>(logger, () => { action.Invoke(); return 0; }, customMsg);
    public static TOut TryCatchErrors<TLogger, TOut>(ILogger<TLogger> logger, Func<TOut> action, string? customMsg = null)
    {
        try 
        {
            if (logger == null) { throw new ArgumentNullException($"Got null for logger", $"Expected type ILogger<{typeof(TLogger).AssemblyQualifiedName}>!"); }
            if (action == null) { throw new ArgumentNullException($"Got null for action", $"Expected type Func<{typeof(TOut).AssemblyQualifiedName}>!"); }
            return action.Invoke(); 
        }
        catch (Exception e)
        {
            logger.LogError(e, customMsg ?? e.Message);
        }
    }
}

Когда я выполняю следующий пример моего предполагаемого использования вышеупомянутого, моя функция-обертка не может поймать ошибку:

    public static async Task DeleteRecords<TLog>(ILogger<TLog> _logger) =>
        await ErrorHandling.TryCatchErrors(_logger, async () =>
        {
            // Other functionality that might throw an unexpected error etc.

            throw new Exception();
        });

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

Заранее спасибо!

1 Ответ

3 голосов
/ 04 мая 2020

Это потому, что вы возвращаете задачу, возвращенную из параметра Func<TOut> action напрямую. Это означает, что задача не может быть выполнена внутри try / catch в TryCatchErrors. На данный момент он работает только как прокси, передавая задачу вызывающей стороне.

Сделайте это asyn c и дождитесь его там. Делая это asyn c и ожидая его внутри метода, вы делаете его частью машины состояний. Так что try / catch также будет частью этого.

public async static TOut TryCatchErrors<TLogger, TOut>(ILogger<TLogger> logger, Func<TOut> action, string? customMsg = null)
{
    try 
    {
        if (logger == null) { throw new ArgumentNullException($"Got null for logger", $"Expected type ILogger<{typeof(TLogger).AssemblyQualifiedName}>!"); }
        if (action == null) { throw new ArgumentNullException($"Got null for action", $"Expected type Func<{typeof(TOut).AssemblyQualifiedName}>!"); }
        await action.Invoke(); 
    }
    catch (Exception e)
    {
        logger.LogError(e, customMsg ?? e.Message);
    }
}

Я не проверял это, но я думаю, что вы должны изменить сигнатуру методов на:

public async static Task<TOut> TryCatchErrors<TLogger, TOut>(ILogger<TLogger> logger, Func<Task<TOut>> action, string? customMsg = null)
{
    try 
    {
        if (logger == null) { throw new ArgumentNullException($"Got null for logger", $"Expected type ILogger<{typeof(TLogger).AssemblyQualifiedName}>!"); }
        if (action == null) { throw new ArgumentNullException($"Got null for action", $"Expected type Func<{typeof(TOut).AssemblyQualifiedName}>!"); }
        await action.Invoke(); 
    }
    catch (Exception e)
    {
        logger.LogError(e, customMsg ?? e.Message);
    }
}

, иначе вы Вам, вероятно, не позволено его ждать.

...