Using raw exceptions instead of Contains ()?

Imagine that the object you are working with has a collection of other objects associated with it, for example, the Controls collection in WinForm. You want to check for a specific object in the collection, but there is no Contains() method in the collection. There are several ways to handle this.

  • Implement your own Contains() method by looking at all the elements in the collection to see if one of them is what you are looking for. This seems to be a "best practice" approach.
  • I recently came across some code where instead of a loop there was an attempt to access an object inside a try statement, as shown below:
 try { Object aObject = myCollection[myObject]; } catch(Exception e) { //if this is thrown, then the object doesn't exist in the collection } 

My question is: how bad do you think of the second programming practice and why? How is performance compared to a loop in a collection?

+6
c # error-handling
source share
8 answers

I would say that this is a pretty bad practice. While some people may be happy to say that a collection loop is less effective at eliminating an exception, there is overhead for eliminating the exception. I would also ask why you use a collection to access an item by key when a dictionary or hash table is best for you.

My main problem with this code, however, is that no matter what type of exception you throw, you will always have the same result.

For example, an exception may be thrown because the object does not exist in the collection either because the collection itself is null or because you cannot drop myCollect [myObject] into aObject.

All of these exceptions will be handled in the same way that might not be your intention.

Here are some good articles on when and where an exception is usually considered valid:

I especially like this quote from the second article:

It is important that exceptions are thrown only when unexpected or invalid activity occurs that prevents the method from completing a normal function. Exception handling introduces small overhead and reduces performance should not be used for normal program flow instead of conditional processing. It can also be difficult to maintain code that abuses exception handling in this way.

+2
source share

The general rule is to avoid using exceptions for the control flow, unless the circumstances that cause the exception are “exceptional” - for example, extremely rare!

If this is what will happen normally and regularly, it should definitely not be considered an exception.

The exceptions are very, very slow because of all the overhead, so there may be business reasons if this happens often enough.

+4
source share

Exceptions must be exceptional.

Something like "The collection is missing because the database fell out of it" is exceptional

Something like “no key” is normal behavior for a dictionary.

For your specific winforms control collection example, the Controls property has a ContainsKey method that you should use.

There is no ContainsValue , because when you are dealing with dictionaries / hash tables, there is no quick way to not iterate over the entire collection, checking if something is present, so you really are not recommended to do this.

As for WHY, Exceptions should be exceptional, that's about 2 things

  • An indication of what your code is trying to do. You want your code to be consistent with what it is trying to achieve, to the extent possible, to be readable and maintainable. Exception handling adds a bunch of extra missiles that interfere with this goal.

  • Brevity of code. You want your code to do what it does most directly, so it is readable and maintainable. Again, the cool added by exception handling prevents this.

+1
source share

If at the time of writing the code you expect this object to be in the collection, and then at runtime you find that it is not, I would call it an exceptional case and use the exception correctly.

However, if you simply check for the existence of an object, and you find that it does not exist, this is not exceptional. Using an exception in this case is incorrect.

Runtime performance analysis depends on the actual collection used and the search method. It does not matter. Do not let the illusion of optimization fool you into writing confusing code.

0
source share

I would have to think about it more about how I like it ... my gut instinct, ah, not so much ...

EDITOR: Ryan Fox's comments on the exceptional case are ideal, I agree

In terms of performance, it depends on the collection indexer. C # allows you to override the indexer operator, so if it executes a for loop similar to the contains method you would write, then it will be just as slow (maybe a few nanoseconds slower due to try / catch ... but there is nothing to worry about about if this code itself is not in a huge loop).

If the index is O (1) (or even O (log (n)) ... or something faster than O (n)), then the try / catch solution will certainly be faster.

Also, I assume that indexer throws an exception, if it returns null, you can of course just check for null and not use try / catch.

0
source share

In general, using exception handling for thread and program logic is bad practice. I personally consider the latter option to be an unacceptable use of exceptions. Given the features of the languages ​​that are commonly used today (for example, Linq and lambdas in C #, for example), there is no reason not to write your own Contains () method.

As a final thought, today most collections already have a contains method. Therefore, I believe that this is not a problem.

0
source share

Take a look at this blog post from Krzystof: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Exceptions should be used to report errors, but they should not be used as control logic (especially when there are simpler ways to determine the state, such as Contains).

Part of the problem is that exceptions, while not expensive to throw, are expensively caught, and all exceptions are caught at some point.

0
source share

The latter is an acceptable solution. Although I would definitely catch the specific exception (ElementNotFound?) That the collection throws in this case.

Speed, it depends on the general case. If you are more likely to find an element than not, the solution for exclusion will be faster. If you are more likely to fail, it will depend on the size of the collection and its iteration speed. In any case, you would like to measure against normal use to see if this is really a bottleneck before worrying about that speed. Make it clear first, and the last decision is much clearer than the first.

-2
source share

All Articles