2010-07-07 5 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: типа вы дали это не может быть массивом, или является открытым универсальным. Поскольку вы вытаскиваете эти типы данных из фиксированного списка, вы должны знать 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); 

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

+0

+1 исключение аргумента - исключения использования и никогда не должны быть пойманы; использование должно быть гарантировано вызывающим абонентом. Если вы используете контракты с кодом для объявления и принудительного использования ограничений использования, он по умолчанию будет вызывать неуправляемое исключение ContractException, что является еще одной причиной не улавливать исключения использования, поскольку шаблон не будет работать во всех случаях. –

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

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

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

2

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

Единственное исключение, которое, кажется, вы не можете предотвратить, это 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 || пойдено isNullReferenceException || ...)', которое IDE позволит вам разделить на несколько строк для лучшей читаемости. Этот шаблон полезен, когда может быть выбрано несколько исключений, но эти конкретные исключения не могут/не должны обрабатываться. –

Смежные вопросы