简体   繁体   中英

Need some clarification about the static constructor VS static field initializer story in C#

A couple of days ago I asked myself about the difference, if any, between initializing static fields via the static constructor and doing so by using a static field initializer (inline initialization of a static field at the point of declaration).

After reading plenty of stackoverflow questions on the subject and the famous Jon Skeet's article on the beforefieldinit flag I've now a much better understanding of the difference between the two initialization strategies.

There is one point that I'm not sure about, mostly because I wasn't able to find any official documentation about it.

The static construcutor is guaranteed to be executed only once and I think this holds true even in multi threading scenarios (when different threads create instances of the class and / or use static members of the class. In any case, the static constructor runs once and only once).

Is this true even for the inline initialization of the static fields? Is the inline initialization of a static field guaranteed to be executed once even in multi threaded scenarios?

Another point I'm still missing is what are the practical consequences of this difference in the initialization of the static fields of a class. Put another way, I would like to understand when the correctness of a piece of code can be affected by the choice of initializing a static fied inline at the point of declaration (instead of using the static constructor).

Most of the time (this depends mostly on the type of code that I usually work on, namely web applications) I use static readonly fields in service classes to store things that are used by the service I'm writing to perform computations or taking decisions. I decide to put these things inside static fields because they need to be the same for all the possible instances of the class I'm writing, they are actually invariants that don't belong to a particular instance, but instead they belong to the algorithm itself.

This is an example:

public class SomeInterestingService 
{
   private static readonly int ConstantNumber = 13;
   private static readonly string[] Names = new[] { "bob", "alice" };

   private readonly INumberGenerator numberGenerator;

   public SomeInterestingService(INumberGenerator numberGenerator)
   {
      this.numberGenerator = numberGenerator ?? throw new ArgumenNullException(nameof(numberGenerator));
   }

   public int ComputeMagicNumber() 
   {
      int answer = this.numberGenerator.GetNumber();

       foreach(var name in names)
       {
          answer += name.Length;
       }

       answer += ConstantNumber;
       return answer;
   }
}

In code like this, is there any practical difference in chosing static constructor initialization or inline initialization of the static fields ConstantNumber and Names , apart from the difference in performance (inline initialization is more performant due to runtime optimizations that are not possible when using the static constructor)?

Can the correctness of the code above be affected by the coiche in any strange corner case? (I think not)

Original question:

In code like this, is there any practical difference in chosing static constructor initialization or inline initialization of the static fields ConstantNumber and Names, apart from the difference in performance (inline initialization is more performant due to runtime optimizations that are not possible when using the static constructor)?

The answer is no. Either those properties are set upon each construction of the class (instance properties) or set upon the first call to any of the members or methods to the class (static properties).

What @Henk Holterman is saying that because the array of names is a reference type you could theoretically change any of the values in the array. Like:

Names[0] = "Henk Holterman";

Even though the property is readonly. Meaning, you can't assign a new instance of array to that property. The values in the array are not readonly. And could be manipulated if public or by calling a method of that class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM