No, that’s a complete misconception. You initialize your Dictionary with a field initializer. Field initializer are not magic. They are also code that is executed. Static readonly fields are essentially initialized in the static constructor of the class. Look at this example code:
// Inside another class
public class MyData
{
public string a;
public int b;
public MyData(string aA, int aB)
{
a = aA;
b = aB;
}
}
public static Dictionary<string, MyData> Data = new Dictionary<string, MyData>()
{
{"First",new MyData("blubb",42) },
{"Second",new MyData("some data",123) },
{"Third",new MyData("more data",456) }
};
This would result in this IL code:
generated IL code
// this is the actual dictionary field
.field /* 04000021 */ public static class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData> Data
// this is the static constructor of the outer class
.method /* 060000EB */ private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Method begins at RVA 0x6d84
// Code size 86 (0x56)
.maxstack 5
// Data = new Dictionary<string, MyData>
// {
// {
// "First",
// new MyData("blubb", 42)
// },
// {
// "Second",
// new MyData("some data", 123)
// },
// {
// "Third",
// new MyData("more data", 456)
// }
// };
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData>::.ctor() /* 0A000124 */
IL_0005: dup
IL_0006: ldstr "First" /* 70000B61 */
IL_000b: ldstr "blubb" /* 70000B6D */
IL_0010: ldc.i4.s 42
IL_0012: newobj instance void MainForm/MyData::.ctor(string, int32) /* 0600013F */
IL_0017: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData>::Add(!0, !1) /* 0A000125 */
// (no C# code)
IL_001c: nop
IL_001d: dup
IL_001e: ldstr "Second" /* 70000B79 */
IL_0023: ldstr "some data" /* 70000B87 */
IL_0028: ldc.i4.s 123
IL_002a: newobj instance void MainForm/MyData::.ctor(string, int32) /* 0600013F */
IL_002f: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData>::Add(!0, !1) /* 0A000125 */
IL_0034: nop
IL_0035: dup
IL_0036: ldstr "Third" /* 70000B9B */
IL_003b: ldstr "more data" /* 70000BA7 */
IL_0040: ldc.i4 456
IL_0045: newobj instance void MainForm/MyData::.ctor(string, int32) /* 0600013F */
IL_004a: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData>::Add(!0, !1) /* 0A000125 */
// }
IL_004f: nop
IL_0050: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class MainForm/MyData> MainForm::Data /* 04000021 */
IL_0055: ret
} // end of method MainForm::.cctor
This was extracted using ILSpy from the actual compiled code.
As you can see, the initialization of your Dictionary is not magic, but simple linear code that is executed line by line. All the class instances have to be created and added to the dictionary, one by one.
All reference types need to be created on the heap, so there has to be some code which actually creates them. A dictionary is a class that internally usually holds two arrays, one that does the hash referencing and one that actually contains the elements. Objects in OOP needs to be created at some point.
There are rare exceptions, especially when it comes to attributes. Attributes are metadata which is part of the type information. The instances of those classes are loaded from somewhat serialized data as they will appear in memory. Though this also depends on the complexity of the attribute and those aren’t considered “normal” classes anyways as they are part of the reflection / type system.
So assuming that hardcoding data into code somehow makes it load faster it not true.
ps: I actually find it kinda interesting that the generated initialization code does not even set the capacity of the dictionary when it creates the dictionary. That means each Add call will actually make it grow dynamically. So it would create quite a bit of garbage when you have many elements. Though loading the data at runtime from json or csv has essentially the same issue as the number of elements are not known in advance. Though even when we talk about a million entries, this should still be quite fast.