문제

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?

도움이 되었습니까?

해결책

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.

다른 팁

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.

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.

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.

You can guarantee 4 will always come after 2 (if you don't create a instance of your class from your static method), however the same is not true for 1 and 3.

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.

The CLR guarantees that the static constructor runs before any static members are accessed. However, your design is a bit smelly. It would be more straightforward to do something like this:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

With your design, if authentication fails, the only way to prevent MyMethod from running is by throwing an exception.

It's ensured that a static class's constructor has been called before any of its methods get executed. Example:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

Output:

Press enter

// after pressing enter

Hi incoming ...

Hi there!

Hi there!

Here's the actual order in which things go down:

  1. Start of Main
  2. Start of the static MyClass constructor
  3. End of the static MyClass constructor
  4. Start of MyMethod
  5. End of Main

Or you could step through in the debugger.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top