views:

90

answers:

4

Is there any reason to favor one of these approaches over the other when inserting into a generic dictionary with the possibility of a key conflict? I'm building an in-memory version of a static collection so in the case of a conflict it doesn't matter whether the old or new value is used.

If Not mySettings.ContainsKey(key) Then
    mySettings.Add(key, Value)
End If

Versus

mySettings(key) = Value

And then of course there is this, which is obviously not the right approach:

Try
    mySettings.Add(key, Value)
Catch
End Try

Clearly the big difference here is that the first and second approaches actually do different things, but in my case it doesn't matter. It seems that the second approach is cleaner, but I'm curious if any of you .net gurus have any deeper insight. Thanks!

A: 

I agree that since you don't care which value you get, all three get the job done, though they do different things (the first and third keep the original value, while the second always gets the latest value).

I also agree that the second is cleanest, and that the third is a bad idea because it relies on exceptions for an unexceptional situation.

Matthew Flaschen
+2  A: 

If you don't care which element is used in the case of a conflict, I would personally favor:

mySettings(key) = Value

This will cause mySettings to contain the new element, since Item will replace the existing element.

If you would prefer the old value to remain, then your first option is the best, since it will not Add unless the key is unique.

If Not mySettings.ContainsKey(key) Then
    mySettings.Add(key, Value)
End If

This behavior is different than the option above - mainly because the old Value will remain in the Dictionary for the specified key.

I would not use the third option - It will provide the same behavior as the ContainsKey option above, but add overhead due to (non-obvious) exception handling.

Reed Copsey
+3  A: 

Assuming as you say that replacing or not doesn't matter, and we want to get really picky:

Option 1 advantages:

  • It makes it more clear that key duplicates are expected and okay.
  • though trivial, it should be slightly faster in cases where there are many duplicates, because it will often avoid a needless assignment. This performance difference would be so small it would be difficult to perceive even with testing..

Option 2 advantages:

  • Saves lines of code, though in most situations that's not a big advantage. Helpful if the code is in some tight place, like a statement lambda or something.

Unless the tighter code is needed, I vote option 1. I guess. Either is fine.

Edit: After the discussion in the comments below and thinking about it more, I think option 2 will usually be faster. Only when there is a very small set of values and a very large amount of duplication would Option 1 possibly be faster.

Patrick Karcher
I am not sure about the effeciency difference. The first option does two searches of the dictionary (in the case of a new value) while the second (probably) does only one. I think it would have to be benchmarked to find any performance distinction. But as you say, the difference would be trivial regardless.
Jeffrey L Whitledge
Right. I did specify *if there were many duplicates*. If not, then option 2's always-assign would not be a disadvantage, and option 1 would be doing a double lookup (even though very efficient) and assigning anyway. So, depends on the situation. Though as we agree, the difference is trivial either way.
Patrick Karcher
@Patrick: Just FYI - Option 2 will be faster in general. The Contains() check is nearly identical to the internal code used by option 2 (except for a single value assignment). In option 1, you're doing the check 2x (since add does it again), so it would take almost every call being a duplicate to make up for the perf. difference of the single assignment...
Reed Copsey
I do agree with your first statement (although, only marginally, since using Item[] suggests that too) - but the other option really is incorrect.
Reed Copsey
A: 

As options 1 and 2 do different things, so which is most appropriate will depend on your situation.

For example, I have a thread-safe dictionary class which is used for caching immutable items that are essentially interchangeable. In this case, I have overridden the Add method to use your option 2 (protected by appropriate synchronisation of course). This means multiple threads can add items without a race condition, with "last update wins" semantics.

On the other hand, if the dictionary is storing mutable items, option 1 may well be essential as you won't want to silently overwrite an existing item.

Joe