2009-10-21 144 views
2

大家好,我想各地传递方法块作为参数传递给该建在异常处理的辅助类,但它的那些东西一个是直观的,我想将其提交批评,见解或建议。高阶函数法

我想指出了前面,这是不是我怎么做我所有的异常处理,但也有在那里我发现这种结构更多的情况下“可读性”。

例如,我有一个场景,我正在显示预览图像,但如果失败(这是一个真实场景,我正在预览图像,某些GIF/BMP格式无法预览),这只是一个场景,我显示替代图像而不是预览。在try/catch代码块,看起来像这样:

try 
    { 
     alternatePreviewImage.SetSource(fs); 
    } 
    catch (Exception ex) { 
     requiresSpecialPreview = false; 
     previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative)); 
    } 

所以我会利用一个辅助类,需要一个方法参数,使它看起来像这样:

if(!ErrorHelper.RunWithSuccessNotify(()=> alternatePreviewImage.SetSource(fs))){ 
     requiresSpecialPreview = false; 
     previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative));        
    } 

的ErrorHelper.RunWithSuccessNotify是很简单:

public static bool RunWithSuccessNotify(Action code) { 
    bool success = true; 
    try 
    { 
     code(); 
    } 
    catch (Exception ex) 
    { 
     success = false; 
    } 

    return success; 
} 

让我再次强调,这是对这些低撞击场景,以及在那里我也许能抑制异常有用的人:

public static void RunWithErrorSuppression(Action code) { 
    try 
    { 
     code(); 
    } 
    catch (Exception ex) 
    { 
     // pass 
    } 
} 

该方法可以更细致也允许捕获异常:

public static void ExecuteWithLogging(Action code, Action<Exception> handles) { 
     try 
     { 
      code(); 
     } 
     catch (Exception ex) 
     { 
      handles(ex); 
     } 
    } 

那么,什么是这套战术的集中异常处理的想法?如果这是一个糟糕的方向,有什么具体原因可能导致我陷入麻烦?

回答

0

你好,我不知道它是否很好地扩展,但现在我的团队是在我们的测量软件用它来处理特殊的例外(如一些测量设备通信丢失),然后重新启动在这种情况下测量。

现在它的工作很好,特别是在情况下,代码的重要/非重复的部分是在函数(Action参数)被调用,并在异常处理不是真的。

最好的情况是,它们甚至可以是嵌套的并且主代码保持可读的。

另一方面,你正在隐藏你的异常处理在函数名后面做了什么,所以它应该是简单的或足够清楚的,只需通过函数的名称就可以理解,否则你是在混淆未来的某些东西代码的读者(包括你自己)

3

我会用这种方法捕获Exception的主要问题通常被认为是不好的形式。如果有某种方法可以指定要捕获哪种类型的异常,我可能会购买它,但我相信必须在编译时指定。对于捕捉所有例外情况并重新推出不匹配的例外情况,我也感到不太舒服。

记住,当你发现一个异常,你基本上说,你可以在一些有意义的方式处理错误。很显然,上面的代码无法处理StackOverflowExceptionMissingMethodException

+0

小细节:除非您自己抛出,否则在近期版本的框架中无法捕捉到'StackOverflowException'。 – Joren 2009-10-21 21:46:35

+2

您可以在其中指定预期异常的通用版本 – 2009-10-21 21:50:54

+1

Vinko的好处,尽管我仍然没有看到该解决方案如何更易于维护,表达,可读或高性能。 (是的,我故意将性能放在最后。) – Lee 2009-10-21 22:05:12

-1

如果我明白你想要做什么,然后感觉太可怕了我作为一个标准误差的管理模式。那是一个警告信号,因为我花了一段时间来掌握你的想法。

除非有一个很好的理由,代码应该在明确的方法可用于任何维护开发人员可以查看和修改,而不是从其他地方传来传去。仅仅因为某个功能的存在并不意味着它在大多数情况下都很有用。在这种情况下,我看不到混淆的好处。

顺便说一句,我认为你是nailing the corpse to the wall by catching System.Exception。通常的规则是不要捕获异常,除非您知道异常是什么和/或出于某种原因需要了解异常详细信息。

在未知异常情况下的恢复

一个常用的模式看起来是这样的:

bool exceptionHappened = true; 
try 
{ 
    alternatePreviewImage.SetSource(fs); 
    exceptionHappened = false; 
} 
finally 
{ 
    if (exceptionHappened) 
    {  
     requiresSpecialPreview = false; 
     etc; 
    } 
} 
+0

这样的finally {if(expcetionHappened){..}}与捕获异常有什么不同?可以抛出一些不是从异常派生的东西吗? – harms 2009-12-11 13:08:57

+0

在不需要这样做的情况下捕获异常的问题是,您必须吞下异常(通常不好),或者必须重新抛出异常。 Catch-rethrow扰乱了异常双通机制,因此给出了一个悲惨的调试体验。 – RoadWarrior 2009-12-11 16:45:09

0

我最初的想法很简单,就是通过复杂的匿名委托周围味道不好。没有任何东西阻止某人将具有复杂逻辑的匿名代理转储到ErrorHelper方法中。这样的逻辑变得难以测试。我宁愿只在一个对象中传递逻辑,这对我来说似乎是一个更好理解的技术。对我来说,匿名代理(和lambda)是非常简单的逻辑可扩展性,就像比较逻辑一样。匿名代表的机制是强大的,可以用于其他事情,但拥有巨大的权力会带来巨大的责任。 =)

用您的技术实现的是在运行时干净地更改异常处理策略的能力。但这是一个实际的要求吗?

+1

Lambdas比简单的逻辑有更多的用途。创造性思考。 – ChaosPandion 2009-10-21 22:04:49

+1

啊,谢谢你的指导。我从来没有想过要想出来。我会开始这样做。 呵呵,当然lambda有更多的用处。这是否意味着所有可能的系统性脱钩都应该通过使用lambda来实现?没门。在大多数情况下,我认为面向对象的依赖注入仍然更好。在箱子外面想想。 – 2009-10-21 22:08:50

0

看一看THIS,也许马上拿出就可以了醇”反射了一下。在我看来,喜欢同样的事情完成,但有可能以更完整的方式......这似乎很强大...

1

不要捕获所有异常,参数化一个你想要的:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ProvaException 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      int a = doWithException<int>(divide, 0, typeof(DivideByZeroException), x => 300); 
      Console.WriteLine(a); 
      Console.ReadKey(); 
     } 

     public static int divide(int b) 
     { 
      return 10/b; 
     } 

     public static T doWithException<T>(Func<T, T> a, T param1, Type exType, Func<Exception, T> handFunction) { 
      try 
      { 
       return a(param1); 
      } 
      catch(Exception ex) { 
       if(exType.Equals(ex.GetType())) { 
        return handFunction(ex); 
       } 
       else 
        throw ex; 
      } 
     } 
    } 
} 

不是非常类似C#,但它可以用于相同的情况(当你想抽象处理异常)。

你必须写为每一种功能的不同类型的签名,因为C#不支持钻营。 Veeeeeeeeery无聊。 :d

这不是一个很优雅的解决方案,但它给你的东西是如何工作的函数式语言的暗示。学习很有趣。