C#
programming
dictionary
constants
software development

Creating a constant Dictionary in C

Master System Design with Codemia

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

Introduction

In C#, developers often ask for a "constant dictionary" when what they really need is a dictionary whose contents cannot be changed after initialization. That distinction matters because const in C# only works for compile-time constants such as numbers and strings. A dictionary is an object created at runtime, so the right solution is immutability, not const.

Why const Does Not Work

The const keyword is limited to values the compiler can embed directly into the assembly. A Dictionary<TKey, TValue> is allocated at runtime, so this will not compile:

csharp
1using System.Collections.Generic;
2
3public class BadExample
4{
5    // This is invalid C#.
6    // public const Dictionary<string, int> Ports = new();
7}

That means the real design question is how much protection you need:

  • prevent reassignment of the dictionary reference
  • prevent callers from mutating entries
  • guarantee true immutability for shared application state

Each goal has a slightly different implementation.

static readonly Prevents Reassignment

The simplest pattern is static readonly:

csharp
1using System.Collections.Generic;
2
3public static class HttpStatusTexts
4{
5    public static readonly Dictionary<int, string> Values = new()
6    {
7        [200] = "OK",
8        [404] = "Not Found",
9        [500] = "Internal Server Error"
10    };
11}

This prevents the Values field from being assigned to a different dictionary after type initialization. However, the dictionary itself is still mutable:

csharp
HttpStatusTexts.Values[418] = "I'm a teapot";

So static readonly protects the reference, not the contents. That is good enough for private fields that only trusted code can reach, but it is not enough for a public API.

ReadOnlyDictionary Protects the Public Surface

If you want callers to read entries without changing them, wrap the mutable dictionary in ReadOnlyDictionary.

csharp
1using System.Collections.Generic;
2using System.Collections.ObjectModel;
3
4public static class MimeTypes
5{
6    private static readonly Dictionary<string, string> _values = new()
7    {
8        [".json"] = "application/json",
9        [".html"] = "text/html",
10        [".png"] = "image/png"
11    };
12
13    public static readonly ReadOnlyDictionary<string, string> Values =
14        new(_values);
15}

Callers can read values:

csharp
Console.WriteLine(MimeTypes.Values[".json"]);

But attempts to add or remove items through Values will fail.

This is usually a solid choice for application configuration tables, lookup maps, and public constants exposed by a library.

ImmutableDictionary Gives Stronger Guarantees

If you want true immutability, use ImmutableDictionary from System.Collections.Immutable. Unlike ReadOnlyDictionary, there is no hidden mutable dictionary behind the wrapper.

csharp
1using System;
2using System.Collections.Immutable;
3
4public static class ErrorCodes
5{
6    public static readonly ImmutableDictionary<int, string> Values =
7        ImmutableDictionary<int, string>.Empty
8            .Add(1, "Invalid request")
9            .Add(2, "Permission denied")
10            .Add(3, "Timed out");
11}
12
13Console.WriteLine(ErrorCodes.Values[2]);

If you need a modified version, the API returns a new dictionary rather than changing the old one:

csharp
var updated = ErrorCodes.Values.Add(4, "Not implemented");
Console.WriteLine(ErrorCodes.Values.ContainsKey(4));
Console.WriteLine(updated.ContainsKey(4));

That behavior is especially helpful in concurrent code and in systems where shared state must stay predictable.

Which Option Should You Choose?

Use static readonly Dictionary when the dictionary is internal and only trusted code can access it.

Use ReadOnlyDictionary when you want a simple public read-only view but are comfortable keeping a private mutable backing store.

Use ImmutableDictionary when you want the strongest guarantee that values cannot be changed accidentally.

A practical pattern for many codebases is to keep the implementation simple and return IReadOnlyDictionary<TKey, TValue> from APIs:

csharp
1using System.Collections.Generic;
2using System.Collections.Immutable;
3
4public static class CountryCodes
5{
6    private static readonly ImmutableDictionary<string, string> _values =
7        ImmutableDictionary<string, string>.Empty
8            .Add("CA", "Canada")
9            .Add("US", "United States")
10            .Add("MX", "Mexico");
11
12    public static IReadOnlyDictionary<string, string> Values => _values;
13}

This keeps your interface flexible while preserving safe behavior.

Common Pitfalls

The biggest mistake is assuming readonly means the contents cannot change. It does not. It only means the field cannot point to a different object after initialization.

Another mistake is exposing a mutable Dictionary publicly and trusting callers not to modify it. That creates hidden coupling and makes debugging harder.

Developers also sometimes use ReadOnlyDictionary and forget that the backing dictionary can still change internally. If some other code keeps a reference to the original dictionary, the "read-only" view will reflect those mutations.

Finally, avoid overusing const terminology when discussing collection types. In C#, collections are runtime objects, so immutability is the concept that actually applies.

Summary

  • You cannot declare a Dictionary as const in C#.
  • 'static readonly prevents reassignment but not mutation of entries.'
  • 'ReadOnlyDictionary exposes a safer public read-only wrapper.'
  • 'ImmutableDictionary provides true immutable collection behavior.'
  • Pick the option that matches your API and mutation requirements.

Course illustration
Course illustration

All Rights Reserved.