Эффективные методы обработки исключений - PullRequest
3 голосов
/ 07 июля 2010

Я пишу приложение на 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 ]

11 голосов
/ 07 июля 2010

Из этого списка есть только 4 исключения, которые я бы рассмотрел:

  • NotSupportedException
  • ArgumentNullException
  • ArgumentOutOfRangeException
  • ArgumentException

Два других вы никогда не должны поймать, и с более поздними версиями CLR вы не можете поймать ситуацию с OOM (рассмотрите MemoryFailPoint , если вам нужно узнать).

Погружаясь глубже в Array.CreateInstance, мы видим, почему каждый из этих четырех будет брошен:

  • NotImplementedException: тип, который вы указали, не может быть массивом или открытым универсальным. Поскольку вы извлекаете эти типы данных из фиксированного списка, вы должны знать a priori , что это допустимые типы. Я бы не согласился с обработкой этого исключения.
  • ArgumentNullException: вы должны быть уверены, что все передаваемые вами аргументы не равны нулю, поэтому этого никогда не произойдет, и вам не следует обрабатывать это исключение.
  • ArgumentOutOfRangeException: одна из длин меньше 0, которую вы можете проверить a priori , поэтому вам не следует обрабатывать это исключение.
  • ArgumentException: Выдается, если тип недействителен (вы уже убедились, что он действителен) или если длины недостаточно, что вы можете проверить a priori .

Итак, мой предложенный код будет:

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

Таким образом, я бы не стал обрабатывать какие-либо исключения, поскольку вы должны быть в состоянии предотвратить их возникновение, и вам не следует беспокоиться о случаях, когда вы не можете обработать исключение.

2 голосов
/ 07 июля 2010

Глядя на документацию для Array.CreateInstance, кажется, что большинство этих исключений выдается из-за нарушения предварительных условий, которые вы можете проверить перед вызовом метода. Например, ArgumentNullException можно предотвратить, убедившись, что передаваемые аргументы не равны NULL, а NotSupportedException можно предотвратить, убедившись, что тип, который вы запрашиваете, поддерживается. Поскольку у вас, кажется, есть комбинированный список, содержащий используемый тип, это должно быть довольно просто.

Единственное исключение, которое, кажется, вы не можете предотвратить, - это OutOfMemoryException, который, возможно, не стоит пытаться поймать.

0 голосов
/ 07 июля 2010

Очевидный ответ здесь заключается в проверке параметров перед их передачей в метод 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 голосов
/ 07 июля 2010

Я полагаю, что вы пытаетесь отразить базовый тип исключения, чтобы попытаться получить конкретное сообщение:

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

однако, если вам нужно что-то сделать, кроме выбора строкового сообщения, вам нужноделайте то, что вы написали в своем вопросе, и обрабатывайте каждый по отдельности.

хотя, я полагаю, вы могли бы также создать делегат Словарь типов для действия <> ... не уверен, что это запах кода, хотя,;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...