What is performance of ContainsKey and TryGetValue?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Dictionary lookups in C# are usually very fast, but there is still a meaningful difference between ContainsKey and TryGetValue depending on what you need. If you want both existence and the stored value, TryGetValue is normally the better choice because it avoids doing the lookup twice.
What the Two Methods Actually Do
ContainsKey answers one question: does this key exist.
TryGetValue answers two questions at once: does the key exist, and if so, what is the value.
Both methods use the dictionary's hash-based lookup machinery, so in normal conditions both are expected to be close to constant time. The important performance distinction is not that one is O(1) and the other is not. The real difference is whether you perform one lookup or two.
The Double-Lookup Pattern
This is a very common pattern:
It works, but it often performs redundant work:
ContainsKeysearches for the key- the indexer
dictionary[key]searches again
That means extra hashing and bucket traversal. In a small dictionary it may not matter much, but it is still unnecessary.
The preferred version is:
Now the lookup happens once.
When ContainsKey Is Fine
ContainsKey is still a good method when you genuinely only care about presence.
If no value is needed, TryGetValue can feel awkward because it forces you to name an out variable you may never use.
So the practical guideline is simple:
- use
ContainsKeyfor presence only - use
TryGetValuewhen you want the value too
A Small Benchmark-Style Example
You do not need a benchmarking framework to understand the shape of the cost. This simple example shows the more efficient pattern for repeated reads:
This avoids exceptions for missing keys and avoids the double lookup of ContainsKey plus indexer access.
Why Missing-Key Behavior Matters Too
Performance is not the only reason TryGetValue is preferred in many code paths. The indexer throws KeyNotFoundException when the key is absent, while TryGetValue gives you a branch-friendly boolean result.
That makes code both faster and clearer when missing keys are expected:
This is usually better than:
Exceptions are for exceptional situations, not normal control flow.
What About Worst Cases
Dictionary operations are fast on average, but hash collisions can make any hash-table operation slower. In ordinary application code with a sane comparer and normal key distribution, that is rarely the deciding factor between these two methods. The bigger concern is still avoiding unnecessary repeated lookups.
Common Pitfalls
- Using
ContainsKeyand then the indexer whenTryGetValuewould do both jobs in one lookup. - Choosing the indexer for uncertain keys and then handling missing entries with exceptions.
- Assuming
ContainsKeyis somehow safer thanTryGetValue. The safer method is the one that matches what the code needs. - Over-optimizing microbenchmarks while ignoring clarity. The rule is simple: one lookup is better than two.
- Forgetting that custom comparers affect dictionary behavior. Poor comparer choices can hurt all lookup methods.
Summary
- '
ContainsKeyandTryGetValueare both fast average-case dictionary operations.' - If you need the value,
TryGetValueis usually better because it avoids a second lookup. - If you only need to know whether a key exists,
ContainsKeyis perfectly appropriate. - '
TryGetValuealso avoids throwing exceptions for expected missing keys.' - The main performance lesson is not complexity class, but avoiding redundant work.

