How does a static constructor work?

10,797

Solution 1

You only asked one question here but there are a dozen or so questions that you should have asked, so I'll answer them all.

Here is the sequence which I assumed

  1. Start of class constructor (also known as cctor)
  2. End of cctor
  3. start of Main
  4. start of MyMethod

Is this correct?

No. The correct sequence is:

  1. Start of cctor for Program, if there is one. There is not.
  2. End of cctor for Program, if there is one. There is not.
  3. Start of Main
  4. Start of cctor for MyClass
  5. End of cctor for MyClass
  6. Start of MyClass.MyMethod

What if there is a static field initializer?

The CLR is permitted to change the order in which static field initializers run in some cases. See Jon's page on the subject for details:

The differences between static constructors and type initializers

Is it ever possible for a static method like MyMethod to be called before the cctor of that class completes?

Yes. If the cctor itself calls MyMethod then obviously MyMethod will be called before the cctor completes.

The cctor does not call MyMethod. Is it ever possible for a static method like MyMethod to be called before the cctor of MyClass completes?

Yes. If the cctor uses another type whose cctor calls MyMethod then MyMethod will be called before the MyClass cctor completes.

No cctors call MyMethod, directly or indirectly! Now is it ever possible for a static method like MyMethod to be called before the cctor of MyClass completes?

No.

Is that still true even if there are multiple threads involved?

Yes. The cctor will finish on one thread before the static method can be called on any thread.

Can the cctor be called more than once? Suppose two threads both cause the cctor to be run.

The cctor is guaranteed to be called at most once, no matter how many threads are involved. If two threads call MyMethod "at the same time" then they race. One of them loses the race and blocks until the MyClass cctor completes on the winning thread.

The losing thread blocks until the cctor is done? Really?

Really.

So what if the cctor on the winning thread calls code that blocks on a lock previously taken by the losing thread?

Then you have a classic lock order inversion condition. Your program deadlocks. Forever.

That seems dangerous. How can I avoid the deadlock?

If it hurts when you do that then stop doing that. Never do something that can block in a cctor.

Is it a good idea to rely upon cctor initialization semantics to enforce complex security requirements? And is it a good idea to have a cctor that does user interactions?

Neither are good ideas. My advice is that you should find a different way to ensure that the security-impacting preconditions of your methods are met.

Solution 2

According to the MSDN, a static constructor:

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

So the static constructor will be called before the static method MyClass.MyMethod() is invoked (assuming not also invoked during static construction or static field initialization of course).

Now, if you are doing anything asynchronous in that static constructor, then it's your job to synchronize that.

Solution 3

The #3 is actually #1: static initialization does not start until the first use of the class to which it belongs.

It is possible if MyMethod is called from the static constructor or a static initialization block. If you do not invoke MyMethod directly or indirectly from your static constructor, you should be fine.

Solution 4

From the documentation (emphasis mine):

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

Solution 5

The static constructor will be called before mymethod is executed. However if you are screwed if 4 is called before 2 then I suggest you re-think your design. Should not be doing complicated stuff in a static constructor anyway.

Share:
10,797

Related videos on Youtube

om471987
Author by

om471987

http://omkar.me

Updated on June 12, 2022

Comments

  • om471987
    om471987 about 2 years
    namespace MyNameSpace
    {
        static class MyClass
        {
            static MyClass()
            {
                //Authentication process.. User needs to enter password
            }
    
            public static void MyMethod()
            {
                //Depends on successful completion of constructor
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                MyClass.MyMethod();
            }
        }
    }
    

    Here is the sequence which I assumed

    1. Start of static constructor
    2. End of static constructor
    3. Start of main
    4. Start of MyMethod
    5. End of main

    Now in any scenario if 4 will start before 2 I am screwed. Is it possible?

    • ARRG
      ARRG over 12 years
      Is this a java or c# question ? You've put both tags, and I don't think the specification is the same in the two languages.
    • om471987
      om471987 over 12 years
      In my openion this is work same for both.. But I am C# guy.. Sry for that
    • deraj
      deraj over 12 years
      Java doesn't have a static constructor in the same way, just static blocks for static initialization. static { //do something... }
    • Brian
      Brian over 12 years
      Personally, I feel uncomfortable with any form of interactivity inside a static constructor. I understand your goal (make every method in this static class wait until the user is authorized before allowing it to run), but really dislike this method of accomplishing it.
    • om471987
      om471987 over 12 years
      @Brian:- Yeah... You are right... I was just doing analysis.. Finally I just decided not to use constructor but Initialize method
  • James Michael Hare
    James Michael Hare over 12 years
    Just as a note, it's my understanding that the static initialization can actually be called before first use depending on eligibility for optimizations.
  • Sergey Kalinichenko
    Sergey Kalinichenko over 12 years
  • om471987
    om471987 over 12 years
    using System; namespace MyNameSpace { class Program { static void Main(string[] args) { Console.WriteLine("Entered in main"); Boop.SayHi(); Boop.SayHi(); } } static class Boop { static Boop() { Console.Read(); Console.WriteLine("Constructor key entered"); } public static void SayHi() { Console.WriteLine("Method is called"); } } } yeah this program gives better understanding
  • James Michael Hare
    James Michael Hare over 12 years
    For a static constructor, true, but for static initialization was my point. Sorry, maybe I was just picking nits on the phrase 'static initialization does not start...' that's true for static construction, but not if the class doesn't have a static constructor, then static initialization may happen before.
  • haiyyu
    haiyyu over 12 years
    Possibly. Next time post it as an answer, though. It's more helpful and visible then.
  • James Michael Hare
    James Michael Hare over 12 years
    Sorry, I'm probably just overanalyzing the verbiage. In the context of the question it's absolutely correct, I was just worried about that sentence as a stand-alone statement for static initialization in the context of classes without explicit static constructors.
  • LukeH
    LukeH over 12 years
    @James: You're not overanalysing - the terminology is the crucial difference here. Static constructors are a C# concept, whereas type initialisation is a .NET thing. The code inside a static constructor (C#) becomes part of the type initialiser (.NET), but when and how the type initialiser triggers (ie, the beforefieldinit semantics) is determined by whether or not the C# class has a static constructor.
  • Eric Lippert
    Eric Lippert over 12 years
    If you are doing anything asynchronous that involves a second thread in a static constructor, you are in for a world of pain. Nothing makes deadlocks faster. See stackoverflow.com/a/8883117/88656 for an example.
  • James Michael Hare
    James Michael Hare over 12 years
    @Eric: agreed... I wouldn't want to do that, but wasn't sure form his example what exactly he was wanting to be finished by the time MyMethod was called...
  • Eric Lippert
    Eric Lippert over 12 years
    @JamesMichaelHare: See Jon's page for a thorough discussion of what optimizations are permitted and when: csharpindepth.com/Articles/General/Beforefieldinit.aspx
  • phoog
    phoog over 12 years
    Eric, I am curious why you replaced "static constructor" with "class constructor" or "cctor" in this answer. Is it improper to use "static constructor" when referring to a cctor?
  • Eric Lippert
    Eric Lippert over 12 years
    @phoog: I wanted to be consistent in my use of terminology, so I picked the shortest one. "Static constructor" and "class constructor" are both fine. As an implementation detail, the static constructor of a type is emitted as a special method called ".cctor", so it is common to refer to such a constructor as "a cctor". Were I writing in a more formal context I'd use one of the longer terms.
  • Legends
    Legends over 4 years
    @EricLippert Is this also true for non-static classes with a static constructor?
  • Eric Lippert
    Eric Lippert over 4 years
    @Legends: Is this also true for non-static classes with a static constructor? Yes.