C#
Dictionary
programming
key-value pair
data structures

Difference of Dictionary.Add vs Dictionarykeyvalue

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, Dictionary.Add and indexer assignment both place values into a dictionary, but they do not mean the same thing. Add is a strict insert operation that fails on duplicate keys. Indexer assignment inserts when the key is missing and overwrites when the key already exists. That difference is small in syntax and large in intent.

Add Expresses Insert-Only Semantics

Use Add when a duplicate key should be treated as a bug or an unexpected state. It throws an ArgumentException if the key is already present.

csharp
1using System;
2using System.Collections.Generic;
3
4var counts = new Dictionary<string, int>();
5counts.Add("apples", 3);
6
7try
8{
9    counts.Add("apples", 5);
10}
11catch (ArgumentException ex)
12{
13    Console.WriteLine(ex.Message);
14}

That exception is useful when the code relies on uniqueness and a repeated key would signal bad upstream data or broken control flow.

Indexer Assignment Expresses Upsert Semantics

The dictionary indexer behaves differently. If the key is missing, it inserts a new entry. If the key exists, it replaces the old value.

csharp
1using System.Collections.Generic;
2
3var counts = new Dictionary<string, int>();
4counts["apples"] = 3; // insert
5counts["apples"] = 5; // overwrite

This is convenient when last-write-wins behavior is actually what you want, such as refreshing cached values or applying configuration overrides.

The Right Choice Depends on Domain Rules

The key question is not which syntax is shorter. It is whether duplicates are allowed. If a repeated key should fail loudly, Add makes the rule obvious. If repeated keys should replace earlier values, the indexer is a better fit.

This is one of those cases where API choice documents business logic. A future maintainer can often infer intended behavior directly from the insertion method.

TryAdd Is Often Better Than Catching Exceptions

If duplicate keys are expected sometimes but should not overwrite data, TryAdd is often the cleanest option. It avoids exception-driven control flow and returns a boolean instead.

csharp
1using System.Collections.Generic;
2
3var counts = new Dictionary<string, int>();
4
5bool insertedFirst = counts.TryAdd("apples", 3);
6bool insertedSecond = counts.TryAdd("apples", 9);

That pattern is easier to use in ingestion or merge pipelines where duplicates are part of normal input quality issues rather than truly exceptional failures.

Reads Have Different Semantics Too

Write behavior is only half the story. The indexer inserts on write, but the indexer throws on read if the key is missing. That is why TryGetValue is usually safer when key presence is uncertain.

csharp
1if (counts.TryGetValue("oranges", out var value))
2{
3    Console.WriteLine(value);
4}
5else
6{
7    Console.WriteLine("missing");
8}

Keeping read and write behavior explicit makes dictionary-heavy code much easier to review.

Concurrency Still Matters

None of these insertion APIs make Dictionary<TKey, TValue> safe for concurrent writes. If multiple threads update the same dictionary, use a collection designed for that scenario, such as ConcurrentDictionary.

csharp
1using System.Collections.Concurrent;
2
3var totals = new ConcurrentDictionary<string, int>();
4totals.AddOrUpdate("apples", 1, (_, oldValue) => oldValue + 1);

It is common to focus on duplicate-key semantics and forget that thread safety is a separate decision.

Common Pitfalls

The biggest mistake is using indexer assignment in places where duplicates should fail fast. Another is using Add in high-duplicate workflows and paying unnecessary exception overhead. Teams also often forget that indexer reads and writes behave differently, or they apply the correct insertion API on the wrong collection type in multi-threaded code.

Summary

  • 'Add performs strict insertion and throws on duplicate keys.'
  • Indexer assignment performs upsert behavior and overwrites existing values.
  • 'TryAdd is useful when duplicates are expected but should not overwrite data.'
  • API choice should reflect domain intent, not just convenience.
  • Thread safety is a separate concern from duplicate-key behavior.

Course illustration
Course illustration

All Rights Reserved.