2010-07-07 60 views
3

我正在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) { } 

回答

11

该名单中只有4个例外,我会考虑醒目:

  • NotSupportedException
  • ArgumentNullException
  • ArgumentOutOfRangeException
  • ArgumentException

另外两个你永远不应该赶上,并且从后面的CLR的你不能赶上OOM的情况(如果你需要找出MemoryFailPoint考虑)。

更深入地研究Array.CreateInstance,我们看到为什么每个这四个会被抛出:

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

所以,我建议的代码如下:

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

总之,我不会处理任何异常,因为你应该能够避免所有这些发生,你不应该在乎您无法处理异常的实例。

+0

+1参数例外是使用例外,不应被捕获;用户必须由主叫方保证。如果您使用代码合约来声明和执行使用约束,默认情况下,它将引发无法捕获的ContractException,这是进一步不捕获使用异常的原因,因为该模式在所有情况下都不起作用。 – 2010-07-07 18:26:42

0

我想你做基本异常类型的一些反射来尝试获取特定的消息:,

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

但是如果你需要做任何事情,除了选择一个字符串消息,你需要做的你在问题中发布的内容,并分别处理每个问题。尽管如此,我想你也可以创建一个字典类型到行动<>委托人......不知道这是否是代码味道。 ;)

2

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

唯一的例外,你似乎无法防止的是OutOfMemoryException,可以说你不应该试图捕捉。

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. 
    } 
} 
+0

这是更清洁使用'(捕获是OutOfMemoryException ||捕获是NullReferenceException || ...)',其中IDE将让你分成多行以更好的可读性。当可以抛出多个异常时这种模式很有用,但是这些特殊的异常不能/不应该被处理。 – 2010-07-07 18:38:01