重构异常处理

Ser*_*uss 5 c# refactoring exception

在我的一个类中,我调用了一个存储库,该存储库上有一些错误处理.我想重构错误处理代码,因为它是非常重复的,唯一真正改变的是消息.

我的代码目前看起来像这样:

public IList<User> GetUser()
{
    try
    {
        return _repository.GetUsers();
    }
    catch (WebException ex)
    {
        ErrorMessages.Add("...");
        _logger.ErrorException("...", ex);
    }
    catch (SoapException ex)
    {
       ErrorMessages.Add("...");
        _logger.ErrorException("...", ex);
    }
    ... etc
}
Run Code Online (Sandbox Code Playgroud)

我可以通过调用另一个获取错误消息值和记录器消息值的方法来替换catch块中的那些行.但是我想我也可以使用Action <>参数执行此操作,但我对使用Func <>和Action <>非常缺乏经验,并且我没有真正看到使用其中一个方法对我有什么好处.

我的问题是什么是重构这个代码的最佳方法,为什么一种方式比另一种方式更有利(根据我上面的例子).

谢谢你的帮助.

Mat*_*son 5

您可以使用 lambda 来帮助解决此问题。

如果您定义通用错误处理程序来接受类型的参数,Action那么您可以在错误处理程序中调用该操作。

您无需担心返回值,因为您在调用时编写的 lambda 可以处理该问题。

例如,您的通用处理程序可能如下所示:

public void AttemptAction(Action action)
{
    try
    {
        action();
    }
    catch (WebException ex)
    {
        ErrorMessages.Add("...");
        _logger.ErrorException("...", ex);
        // Rethrow?
    }
    catch (SoapException ex)
    {
        ErrorMessages.Add("...");
        _logger.ErrorException("...", ex);
        // Rethrow?
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

public IList<User> GetUser()
{
    IList<User> result = null;

    AttemptAction(() => result = _repository.GetUsers());

    return result;
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*der 4

假设异常类型始终相同但消息不同,您可以这样做:

static public T Try<T>(string webMessage, string soapMessage, Func<T> func)
{
    try
    {
        return func();
    }
    catch (WebException ex)
    {
        ErrorMessages.Add(webMessage);
        _logger.ErrorException(webMessage, ex);
    }
    catch (SoapException ex)
    {
       ErrorMessages.Add(soapMessage);
        _logger.ErrorException(soapMessage, ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

此 Try 方法将使用类型的委托Func<T>来调用函数并返回其值。该函数将位于同一个 try-catch 块内。这些消息是通过参数提供的。现在,在代码的其他地方,您可以这样调用:

var users = Try("My web message.", "My soap message.", () => _repository.GetUsers());
Run Code Online (Sandbox Code Playgroud)

或者,在您的情况下甚至更短(不使用参数时):

var users = Try("My web message.", "My soap message.", _repository.GetUsers);
Run Code Online (Sandbox Code Playgroud)

Try当然,您可以根据自己的喜好修改和安排参数。

如果您混合使用带和不带返回类型的方法,最好不要使用 ,Func而是使用Action. 这将能够满足所有情况:

static public void Try(string webMessage, string soapMessage, Action action)
{
    try
    {
        action();
    }
    catch (WebException ex)
    {
        ErrorMessages.Add(webMessage);
        _logger.ErrorException(webMessage, ex);
    }
    catch (SoapException ex)
    {
       ErrorMessages.Add(soapMessage);
        _logger.ErrorException(soapMessage, ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

但这个解决方案使代码的阅读/维护变得更加困难:

IList<User> users;
Try("My web message.", "My soap message.", () => users = _repository.GetUsers());
Run Code Online (Sandbox Code Playgroud)