.NET Dictionary get existing value or create and add new value
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
A common C sharp pattern is reading a value from a dictionary if a key exists, or creating a new value when it does not. This appears in counters, grouping maps, caches, and aggregation code. The best implementation depends on whether the dictionary is single-threaded or shared across threads.
Prefer TryGetValue Over ContainsKey Plus Indexer
ContainsKey followed by indexer access performs two lookups and can be noisy in repeated code.
TryGetValue is clearer and avoids duplicate probing.
Create a Reusable GetOrAdd Extension
When this pattern repeats, a helper improves consistency.
This keeps call sites concise and avoids ad hoc implementations.
Include a Creation Flag When Needed
Sometimes callers need to know whether value existed or was created.
This is useful for metrics such as cache hit and cache miss counts.
Threaded Code Requires ConcurrentDictionary
Regular Dictionary is not safe for concurrent writes. For shared mutable state, use ConcurrentDictionary APIs.
For collection values:
Keep factories side-effect free because they may run more than once under contention.
Capacity and Allocation Considerations
For large ingestion jobs, initialize dictionary with estimated capacity.
This reduces resize overhead and improves throughput. Also avoid repeatedly allocating identical default objects when one immutable value is enough.
API Design Guidance
If helper behavior is shared across services, define one extension library with clear semantics:
- does factory run lazily
- does method mutate map in-place
- is method thread-safe or not
Explicit contracts reduce misuse and simplify code review.
Nullable Value Considerations
If dictionary values may be null references, design helper behavior explicitly so missing keys and present-null keys are distinguishable. Clear null semantics prevent subtle cache and grouping bugs.
Common Pitfalls
- Using
ContainsKeyplus indexer in hot paths with repeated lookups. - Sharing
Dictionaryacross threads without synchronization. - Writing value factories that perform external side effects.
- Reusing mutable default instances across different keys.
- Ignoring capacity planning for large key spaces.
Summary
- Use
TryGetValuefor efficient get-or-create logic in single-threaded dictionaries. - Extract reusable
GetOrAddhelpers to reduce boilerplate. - Use
ConcurrentDictionaryfor multi-threaded mutation. - Keep factories idempotent and side-effect free.
- Pre-size dictionaries when handling large workloads.
Related reading
- .NET graph library around?
- .net service bus recommendations?
- New Array from Index Range Swift
- Nice Label Algorithm for Charts with minimum ticks
- .Net dotNet wrappers for OpenCV?
- .Net EF core DbContext.Save during multiple Async functions
- Nice universal way to convert List of items to Tree
- No generic implementation of OrderedDictionary?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.