2008-08-11 7 views
6

Представьте, что у объекта, с которым вы работаете, есть коллекция других связанных с ним объектов, например коллекция элементов управления в WinForm. Вы хотите проверить определенный объект в коллекции, но коллекция не имеет метода Contains(). Существует несколько способов борьбы с этим.Использование необработанных исключений вместо Contains()?

  • Внесите свой собственный метод Contains(), пройдя по пунктам в коллекции, чтобы узнать, есть ли у вас какой-либо из них. Это, по-видимому, подход «наилучшей практики».
  • Недавно я наткнулся на некоторый код, где вместо цикла, была предпринята попытка получить доступ к объекту внутри попробовать заявление следующим образом:
try 
{ 
    Object aObject = myCollection[myObject]; 
} 
catch(Exception e) 
{ 
    //if this is thrown, then the object doesn't exist in the collection 
} 

Мой вопрос, как бедных практика программирования вы считаете вторым вариантом и почему? Какова эффективность его по сравнению с циклом в коллекции?

ответ

2

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

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

Например, исключение может быть выбрано потому, что объект не существует в коллекции или потому, что сама коллекция является нулевой или потому, что вы не можете передать myCollect [myObject] в объект aObject.

Все эти исключения будут обработаны таким же образом, что может и не быть вашим намерением.

Это несколько хороших статей о том, когда и где она Usally считается приемлемым бросать исключения:

Мне особенно нравится эта цитата из второй статьи :

Важно, чтобы исключения a re возникает только в случае неожиданной или недействительной активности, которая предотвращает метод от выполнения его нормальной функции . Обработка исключений вводит небольшие накладные расходы и снижает производительность , поэтому не следует использовать для нормальный программный поток вместо условная обработка. Также может быть сложно поддерживать код, который управляет обработкой исключений в этом способе .

0

Если во время написания кода вы ожидаете, что этот объект будет в коллекции, а затем во время выполнения вы обнаружите, что это не так, я бы назвал это исключительным случаем и правильно использовать исключение.

Однако, если вы просто проверяете существование объекта, и вы обнаружите, что его нет, это не является исключительным. Использование исключения в этом случае неверно.

Анализ производительности во время выполнения зависит от используемой фактической коллекции и метода при поиске. Это не имеет значения. Не позволяйте иллюзии оптимизации обмануть вас в написании путаного кода.

-2

Последний является приемлемым решением. Хотя я определенно поймаю конкретное исключение (ElementNotFound?), Которое коллекция выбрасывает в этом случае.

Speedwise, это зависит от обычного случая. Если вы с большей вероятностью найдете элемент, чем нет, решение для исключения будет быстрее. Если вы с большей вероятностью потерпите неудачу, это будет зависеть от размера коллекции и ее скорости итерации. В любом случае, вы бы хотели измерить против обычного использования, чтобы увидеть, действительно ли это бутылочная горловина, прежде чем беспокоиться о такой скорости. Сначала сделайте ясность, и последнее решение намного яснее первого.

0

я должен думать об этом больше о том, как сильно я люблю его ... мой кишки инстинкт, а не так много ...

EDIT: Комментарии Ryan Фокса на исключительный случай является идеальным , Я согласен

Что касается производительности, это зависит от индексатора в коллекции. C# позволяет вам переопределить оператор индексатора, поэтому, если он выполняет цикл for, подобный методу contains, который вы бы пишете, тогда он будет таким же медленным (возможно, на несколько наносекунд медленнее из-за попытки/catch ... но нечего беспокоиться, если только этот код не находится в пределах огромного цикла).

Если индексом является O (1) (или даже O (log (n)) ... или чем-то быстрее, чем O (n)), то решение try/catch будет, конечно, быстрее.

Кроме того, я предполагаю, что индексщик бросает исключение, если он возвращает null, вы, конечно, можете просто проверить значение null и не использовать try/catch.

0

В общем, использование обработки исключений для потока программы и логики является плохой практикой. Я лично считаю, что последний вариант является неприемлемым использованием исключений. Учитывая особенности языков, обычно используемых в наши дни (например, Linq и lambdas в C#, например), нет причин не писать собственный метод Contains().

В качестве последней мысли, в настоящее время большинство коллекций do есть уже есть способ. Поэтому я думаю, что в большинстве случаев это не проблема.

4

Общее правило заключается в том, чтобы избежать использования исключений для потока управления, если обстоятельства, вызывающие исключение, являются «исключительными» - например, крайне редко!

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

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

1

Исключения должны быть исключительными.

Что-то вроде «Коллекция отсутствует, поскольку база данных упала из-под него» является исключительным

Что-то вроде «ключ нет» нормальное поведение для словаря.

Для вашего конкретного примера коллекции управления winforms свойство Controls имеет метод ContainsKey, который вы должны использовать.

Нет ContainsValue, потому что при работе со словарями/хеш-таблицами нет быстрого пути прохождения итерации всей коллекции, проверки наличия чего-либо, поэтому вам действительно не рекомендуется делать это.

А почему Исключения должны быть исключительными, это около 2 вещей

  1. показывающих, что ваш код пытается сделать. Вы хотите, чтобы ваш код соответствовал тому, чего он пытается достичь, насколько это возможно, чтобы он был читабельным и поддерживаемым. Обработка исключений добавляет кучу дополнительной трещины, которая мешает этим целям.

  2. Краткость кода. Вы хотите, чтобы ваш код выполнял то, что он делает самым прямым способом, поэтому он читабельен и поддерживается. Опять же, крейт, добавленный обработкой исключений, мешает этому.

0

Взгляните на этом блоге от Кшиштоф: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Исключения должны быть использованы для передачи состояния ошибки, но они не должны использоваться в качестве логики управления (особенно, когда есть гораздо более простые способы определить условие, такое как Содержит).

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