Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有效的异常处理技术_C#_.net_Exception Handling_Performance - Fatal编程技术网

C# 有效的异常处理技术

C# 有效的异常处理技术,c#,.net,exception-handling,performance,C#,.net,Exception Handling,Performance,我正在用C#编写一个应用程序,它要求我从用户传入的某些维度动态创建一个数组对象。Array.CreateInstance()方法可以抛出(按上次计数)我想要处理的6个不同的异常。对于每个异常,我希望通过一个简单的MessageBox.Show()和一条针对异常情况定制的消息通知用户。我不想做的是捕获常规异常类型,因为最好不要这样做。我会尝试捕获ArgumentException或更具体的内容,但所有异常的唯一公共超类是Exception 底线:我正在试图找出处理如此多不同异常的最佳方法,以及什么

我正在用C#编写一个应用程序,它要求我从用户传入的某些维度动态创建一个
数组
对象。
Array.CreateInstance()
方法可以抛出(按上次计数)我想要处理的6个不同的异常。对于每个异常,我希望通过一个简单的
MessageBox.Show()
和一条针对异常情况定制的消息通知用户。我不想做的是捕获常规
异常
类型,因为最好不要这样做。我会尝试捕获
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个例外我会考虑:

  • NotSupportedException
  • ArgumentNullException
  • ArgumentOutOfRangeException
  • ArgumentException
另外两个你永远都不应该捕捉到,而在后面的CLR中,你无法捕捉到OOM的情况(如果你需要了解的话,考虑一下)

深入研究
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);

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

我想您应该对基本异常类型进行一些反思,以尝试获取特定的消息:

// 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;
    }
}
//某处。。。
公共静态索引例外消息;
//在你的方法中。。。
试试{…}
捕获(例外情况除外){
var exType=ex.GetType();
if(exceptionMessages.ContainsKey(exType)){
Show(例外消息[exType]);
}
否则{
掷骰子;
}
}
然而,如果您除了选择字符串消息之外还需要做任何事情,那么您需要做您在问题中发布的事情,并分别处理每个问题

尽管如此,我想您也可以创建一个类型字典来操作委托。。。但不确定这是否是一种代码气味

查看
Array.CreateInstance
似乎大多数异常都是由于违反了先决条件而引发的,您可以在调用该方法之前检查这些先决条件。例如,可以通过确保传递的参数不为null来防止
ArgumentNullException
,也可以通过确保支持请求的类型来防止
NotSupportedException
。因为您似乎有一个包含要使用的类型的组合框,所以这应该非常简单


您似乎无法阻止的唯一异常是
OutOfMemoryException
,可以说您无论如何都不应该尝试捕获它。

这里的明显答案是在将参数传递到
数组之前验证参数。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.
    }
}

+1参数异常是使用异常,不应被捕获;使用必须由呼叫方保证。如果您使用代码约定来声明和强制使用约束,默认情况下,它将抛出一个不可修补的ContractException,这是不捕获使用异常的进一步原因,因为该模式不会在所有情况下都起作用。使用
(捕获的是OutOfMemoryException | |捕获的是NullReferenceException | | |…)
,IDE将允许您拆分多行以获得更好的可读性。当可以抛出多个异常,但不能/不应该处理这些特定异常时,此模式非常有用。