The problem

I often see code like this:

public class MyClass
{
    public IReadOnlyCollection<string> MyStrings { get: }
    
    public MyClass()
    {
        MyStrings = new List<string>
        {
            "First",
            "Second",
            "Third"
        };
    }
}

A collection is exposed via the MyStrings property as an IReadOnlyCollection. The collection is populated in the constructor with predefined (hardcoded) values.

Do you see any problems with this approach?

The solution

The main problem with the above code is that the MyStrings collection will be populated everytime an instance of MyClass is created. Imagine that you're creating an instance of MyClass in some ASP.NET Controller for example. That means that for every request towards your controller, a new list will be created.

Now, in this example this isn't the end of the world, but it's still unneccessary.

One could argue that this is "micro-optimization" that has no real world benefits and yes, I agree.

However, all little things adds up and the "fix" for this scenario is really simple.

Since the collection is initalized in the constructor and then remains static...let's actually make it static.

public class MyClass
{
    private static readonly IReadOnlyCollection<string> _myStrings;
    public IReadOnlyCollection<string> MyStrings => _myStrings;
    
    static MyClass()
    {
        _myStrings = new List<string>
        {
            "First",
            "Second",
            "Third"
        };
    }
}

Too me, this code is "better" in two ways.

  1. The intent of the code is a bit more clear, by making it static, when I read the code I immediately think of it as a "global" collection that will only be initialized once.
  2. Since it only will be initalized once, we get the added benefit of a performance "boost" for free. As I said earlier, the main reason for using the static initialization in this case is NOT because we care about the performance. It's to show intent.

The fastest code is the code which does not run

If we can make our code only run once and get the same functionality (and faster performance) with minimal changes to our code, I think it's a no-brainer. This is not micro-optimization, this is just code that's a bit more readable and also just happens to run faster, that's a win-win in my book.

Benchmarks, just because :)

[MemoryDiagnoser]
public class InitializationBenchmark
{
    [Benchmark]
    public IReadOnlyCollection<string> Instance()
    {
        var myClass = new MyClass();
        return myClass.MyStrings;
    }

    [Benchmark]
    public IReadOnlyCollection<string> Static()
    {
        var myClassStatic = new MyClassStatic();
        return myClassStatic.MyStrings;
    }
}
| Method   | Mean       | Error     | StdDev    | Gen0   | Allocated |
|--------- |-----------:|----------:|----------:|-------:|----------:|
| Instance | 16.8912 ns | 0.1127 ns | 0.0999 ns | 0.0134 |     112 B |
| Static   |  0.0141 ns | 0.0096 ns | 0.0080 ns |      - |         - |