高效的异常处理技术

时间:2010-07-07 18:10:05

标签: c# .net exception-handling performance

我正在用C#编写一个应用程序,它要求我从用户传入的某些维度动态创建一个Array对象。Array.CreateInstance()方法可以抛出(按最后计数)6个不同的异常我想要处理。对于每个例外情况,我都希望通过简单的MessageBox.Show()和针对特殊情况量身定制的消息通知用户。我不想做的是捕捉一般Exception类型,因为不这样做是最好的做法。我会尝试捕获ArgumentException或更具体的内容,但所有异常的唯一常见超类是Exception

底线:我正在尝试找出处理这么多不同异常的最佳方法,以及什么是高效且更重要的可维护解决方案。

try
{
    data = Array.CreateInstance(TypeHelper.StringToType(cbDataType.SelectedItem.ToString()), dimensions);
}
catch (OutOfMemoryException) { }
catch (NullReferenceException) { }
catch (NotSupportedException) { }
catch (ArgumentNullException) { }
catch (ArgumentOutOfRangeException) { }
catch (ArgumentException) { }

4 个答案:

答案 0 :(得分:11)

在该列表中,我认为只有4个例外:

  • NotSupportedException
  • ArgumentNullException
  • ArgumentOutOfRangeException
  • ArgumentException

另外两个你永远不应该抓住,而且在后来的CLR中,你无法捕捉到OOM情况(如果你需要找出,请考虑MemoryFailPoint。)

深入研究Array.CreateInstance,我们明白为什么会抛出这四个中的每一个:

  • NotImplementedException:你给它的类型不能是一个数组,或者是一个开放的泛型。由于您从固定列表中提取这些数据类型,因此您应该知道先验这些是有效类型。我反对处理这个例外。
  • ArgumentNullException:你应该确定你传递的所有参数都不是null,因此这种情况永远不会发生,你不应该处理这个异常。
  • ArgumentOutOfRangeException:其中一个长度小于0,您可以测试先验,因此您不应该处理此异常。
  • ArgumentException:如果类型无效(您已经确定它有效)或者如果没有足够的长度,您可以测试先验。 / LI>

所以,我建议的代码是:

// code prior to this point ensures cbDataType only has correct types
// and dimensions has at least 1 dimension and is all greater than or equal to 1
data = Array.CreateInstance(
    TypeHelper.StringToType(cbDataType.SelectedItem.ToString()),
    dimensions);

总之,我不会处理任何异常,因为您应该能够阻止所有异常发生,并且您不应该关心无法处理异常的实例。

答案 1 :(得分:2)

查看Array.CreateInstance ArgumentNullException,似乎大多数异常都是由于违反前提条件而抛出的,这些是您在调用方法之前可以检查的内容。例如,可以通过确保传递的参数不为空来阻止NotSupportedException,并且可以通过确保支持您请求的类型来阻止OutOfMemoryException。由于您似乎有一个包含要使用的类型的组合框,因此这应该非常简单。

似乎无法阻止的唯一例外是{{1}},无论如何你都不应该试图抓住它。

答案 2 :(得分:0)

我想你会对基本的Exception类型做一些反思,试图获取特定的消息:

// somewhere ...
public static IDictionary<Type, string> exceptionMessages;

// in your method ...
try { ... }
catch( Exception ex ) {        
    var exType = ex.GetType();
    if( exceptionMessages.ContainsKey(exType) ) {
        MessageBox.Show( exceptionMessages[exType] );
    }
    else {
        throw ex;
    }
}

但是,除了选择字符串消息之外,如果你需要做任何事情,你需要做你在问题中发布的内容,并分别处理每个消息。

虽然,我想你也可以创建一个行动类型词典&lt;&gt;代表们......不确定这是不是代码味道。 ;)

答案 3 :(得分:0)

这里显而易见的答案是在将参数传递到Array.CreateInstance方法之前验证参数,以便在它们发生之前避免大多数异常。

但是,如果您想要捕获多个异常类型,那么您将不得不使用反射来简化代码。不幸的是(或许它很幸运)catch块不计入可以共享范围块的许多C#构造中。

try
{
}
catch (Exception caught)
{
    Type[] types = 
      { 
        typeof(OutOfMemoryException), 
        typeof(NullReferenceException) 
        // Continue adding exceptions to be filtered here.
      };
    if (types.Contains(caught.GetType()))
    {
        // Handle accordingly.
    }
    else
    {
        throw; // Rethrow the exception and preserve stack trace.
    }
}