关于通用try catch的建议

时间:2012-09-04 00:06:06

标签: c# exception generics

这不是一个问题,而是更多的反馈和想法。我一直在考虑通过内部团队彻底测试的方法的实现。我想写一个通用异常catch方法和报告服务。

我认为这不像“try-catch”块那么容易,但允许使用统一的方法来捕获异常。理想情况下,我想执行一个方法,提供一个故障回调并记录调用方法中的所有参数。

Generic Try-Execute。

public class ExceptionHelper
{
     public static T TryExecute<T, TArgs>(Func<TArgs, T> Method, Func<TArgs, T> FailureCallBack, TArgs Args)
     {
            try
            {
                return Method(Args);
            }
            catch (Exception ex)
            {
                StackTrace stackTrace = new StackTrace();
                string method = "Unknown Method";
                if (stackTrace != null && stackTrace.FrameCount > 0)
                {
                    var methodInfo = stackTrace.GetFrame(1).GetMethod();
                    if (methodInfo != null)
                        method = string.Join(".", methodInfo.ReflectedType.Namespace, methodInfo.ReflectedType.Name, methodInfo.Name);
                }
                List<string> aStr = new List<string>();
                foreach (var prop in typeof(TArgs).GetProperties().Where(x => x.CanRead && x.CanWrite))
                {
                    object propVal = null;
                    try
                    {
                        propVal = prop.GetValue(Args, null);
                    }
                    catch
                    {
                        propVal = string.Empty;
                    }
                    aStr.Add(string.Format("{0}:{1}", prop.Name, propVal.ToString()));
                }
                string failureString = string.Format("The method '{0}' failed. {1}", method, string.Join(", ", aStr));
                //TODO: Log To Internal error system
                try
                {
                    return FailureCallBack(Args);
                }
                catch
                {
                    return default(T);
                }
            }
      }
}

我所知道的是退缩。

  • 使用反射的性能损失
  • MethodBase(methodInfo)可能无法通过优化
  • 获得
  • 错误处理程序周围的try-catch。基本上我可以在错误回调周围使用tryExecute包装器进行try-catch,但这可能会导致堆栈溢出。

这是一个示例实现

var model = new { ModelA = "A", ModelB = "B" };
return ExceptionHelper.TryExecute((Model) =>
{
     throw new Exception("Testing exception handler");
},
(Model) =>
{
    return false;
}, 
model);

赞赏的想法和评论。

2 个答案:

答案 0 :(得分:12)

这是一个很多代码放在catch中,包括两个 try / catch块。如果你问我,看起来有点矫枉过正,风险很大,进一步的异常会掩盖实际的异常并且错误信息会丢失。

另外,为什么return default(T)?返回默认值或空值作为问题的指示通常是非常草率的。如果没有别的,它需要相同的条件包围每个方法的调用,以检查返回并响应...现在已经在其他地方出现的一些错误。

老实说,这个用法示例看起来也很混乱。看起来你最终会用错误捕获代码模糊实际的业务逻辑。整个代码库看起来像一系列错误陷阱,实际的业务逻辑隐藏在它的纠缠中。这需要重点关注应用程序的实际意图,并将一些背景基础架构重要性(日志记录)置于最前沿。

简化。

如果方法中发生异常,通常有两个明智的选择:

  1. Catch(有意义句柄)方法中的异常。
  2. 让异常在堆栈中冒泡到其他地方。
  3. 对于发生它的方法范围的异常,绝对没有没有错误。实际上,异常被设计为完全相同,携带有关所发生事件和位置的有用堆栈信息。 (并且,如果您向异常添加有意义的运行时上下文,它还可以携带有关 why 的信息。)

    事实上,编译器甚至巧妙地暗示了这一点。以这两种方法为例:

    public int Sum(int first, int second)
    {
        // TODO: Implement this method
    }
    
    public int Product(int first, int second)
    {
        throw new NotImplementedException();
    }
    

    其中一种方法将编译,其中一种方法不会。编译器错误将指出并非所有代码路径都返回前一个方法的值。但为什么不是后者呢?因为抛出异常是方法的完全可接受的退出策略。这就是该方法如何放弃它正在做的事情(一个它应该尝试做的事情而没有更多)并且让调用代码处理问题。

    代码应该以明确表达正在建模的业务概念的方式阅读。错误处理是一个重要的基础架构概念,但它只是......基础架构。代码实际上应该尖叫正在建模的业务概念,清晰而简洁。基础设施问题不应妨碍这一点。

答案 1 :(得分:6)

这很少有用。

仅涵盖以下情况:

  1. 该方法具有明确的方法,可以在失败时获得适当的返回值。
  2. 你真的想记录它发生的事。
  3. 现在,2是非常常见的,除了所有种类的例外,但不是1也是如此。

    1当然是罕见的,因为在大多数情况下,如果你能通过X方式为给定参数产生合理的返回值,那么你不会尝试Y首先。

    它还有一个返回default(T)的默认行为 - 所以null或全零 - 如果回退不起作用。

    这只适用于上面你的案例1有“因为我们并不真正关心这个东西做什么”的东西,或者那个被调用的方法永远不会返回null,在这种情况下你然后测试为null,这意味着您的真实错误处理代码就在那里。

    总而言之,你所拥有的是一种方式,通过测试(有时候测试+猜测)而不是真正代码可以捕获的异常,以及那些会导致程序崩溃的异常一个有良好调试信息的清晰的地方会把它变成你不知道在哪里发生了什么的状态,但至少有几十个错误记录在一些东西设法完全降低之前,其中一个可能是实际问题

    当您因特定原因捕获某些异常时,请务必记录异常。请注意,这不是为了帮助查找错误(如果引发了异常,那么有一个错误,你不应该在那里捕获它),但是要取消捕获那里的事实可以隐藏错误 - 即取消通过把捕获物全部放在一起,你是刻意鼓励的效果。 (例如,您希望定期访问的web服务有时无法连接,并且您可以使用缓存数据继续运行几个小时 - 因此您可以捕获故障并从缓存中继续 - 在这里您可以记录,因为如果有错误意味着您是永远不要试图正确地点击网络服务,你只是隐藏了它。)

    让一些非交互式(服务或服务器)应用程序记录到达堆栈顶部的所有异常也是合理的,因为那里没有人注意到异常。

    但例外不是敌人,他们是信使。不要射击信使。