5

在我的一个课程中,我调用了一个对它进行了一些错误处理的存储库。我想重构错误处理代码,因为它非常重复,唯一真正改变的是消息。

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

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
}

我可以用调用另一个方法来替换我的 catch 块中的这些行,该方法采用错误消息值和记录器消息值。但是,我想我也可以使用 Action<> 参数来执行此操作,但是我在使用 Func<> 和 Action<> 方面非常缺乏经验,并且真的不知道使用其中一个参数比使用方法有什么好处。

我的问题实际上是重构此代码的最佳方式是什么,以及为什么一种方式比另一种方式受益(根据我上面的示例)。

谢谢你的帮助。

4

3 回答 3

5

您可以使用 lambdas 来帮助解决这个问题。

如果您将通用错误处理程序定义为接受类型参数,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?
    }
}

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

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

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

    return result;
}
于 2013-05-20T11:35:04.940 回答
3

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

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);
    }
}

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

var users = Try("My web message.", "My soap message.", () => _repository.GetUsers());

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

var users = Try("My web message.", "My soap message.", _repository.GetUsers);

当然,您可以根据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);
    }
}

但是这个解决方案使代码更难阅读/维护:

IList<User> users;
Try("My web message.", "My soap message.", () => users = _repository.GetUsers());
于 2013-05-20T11:34:23.523 回答
0

您可以使用面向方面的编程http://en.wikipedia.org/wiki/Aspect-oriented_programming。将所有重复代码放置到称为方面的特殊类的想法。

您的代码将类似于 PostSharp

[ExceptionLogger]
public IList<User> GetUser()
{
    return _repository.GetUsers();
}
public class ExceptionLogger: OnMethodBoundaryAspect
{
    //getting _logger and ErrorMessages
    public override void OnException(MethodExecutionArgs args)
    {
        ErrorMessages.Add("...");
        _logger.ErrorException("...", ex);
    }
}

对于 c#,您可以使用 PostSharp、Castle.Windsor 或 Unity 框架。

于 2013-05-20T11:36:20.520 回答