[c#] 정적 생성자는 어떻게 작동합니까?

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();
        }
    }
}

내가 가정 한 순서는 다음과 같습니다.

  1. 정적 생성자의 시작
  2. 정적 생성자의 끝
  3. 메인 시작
  4. MyMethod 시작
  5. 메인 끝

이제 어떤 시나리오에서든 4가 2 이전에 시작되면 나는 망했다. 가능합니까?



답변

여기에 한 가지 질문 만 하셨는데 물어 보셨 어야 할 질문이 열두 개 정도 있으니 모두 대답하겠습니다.

내가 가정 한 순서는 다음과 같습니다.

  1. 클래스 생성자 시작 (이라고도 함 cctor)
  2. cctor의 끝
  3. 메인 시작
  4. MyMethod 시작

이 올바른지?

아니요. 올바른 순서는 다음과 같습니다.

  1. 프로그램에 대한 cctor 시작 (있는 경우). 없기.
  2. 프로그램에 대한 cctor의 끝 (있는 경우). 없기.
  3. 메인 시작
  4. MyClass에 대한 cctor 시작
  5. MyClass에 대한 cctor의 끝
  6. MyClass.MyMethod 시작

정적 필드 이니셜 라이저가 있으면 어떻게됩니까?

CLR은 경우에 따라 정적 필드 이니셜 라이저가 실행되는 순서를 변경할 수 있습니다. 자세한 내용은 주제에 대한 Jon의 페이지를 참조하십시오.

정적 생성자와 형식 이니셜 라이저의 차이점

MyMethod해당 클래스의 cctor가 완료되기 전에 같은 정적 메서드 를 호출 할 수 있습니까?

예. cctor 자체가 MyMethod를 호출하면 cctor가 완료되기 전에 분명히 MyMethod가 호출됩니다.

cctor는 MyMethod를 호출하지 않습니다. MyMethodMyClass의 cctor가 완료되기 전에 같은 정적 메서드 를 호출 할 수 있습니까?

예. cctor가 cctor가 MyMethod를 호출하는 다른 유형을 사용하는 경우 MyClass cctor가 완료되기 전에 MyMethod가 호출됩니다.

어떤 cctor도 직접 또는 간접적으로 MyMethod를 호출하지 않습니다! 이제 MyMethodMyClass의 cctor가 완료되기 전에 같은 정적 메서드 를 호출 할 수 있습니까?

아니.

여러 스레드가 관련된 경우에도 여전히 사실입니까?

예. cctor는 모든 스레드에서 정적 메소드를 호출하기 전에 한 스레드에서 완료됩니다.

cctor를 두 번 이상 호출 할 수 있습니까? 두 개의 스레드가 모두 cctor를 실행한다고 가정하십시오.

cctor는 얼마나 많은 스레드가 관련되어 있든 관계없이 최대 한 번 호출되도록 보장됩니다. 두 스레드가 MyMethod를 “동시에”호출하면 경쟁합니다. 그들 중 하나는 MyClass cctor가 우승 스레드에서 완료 될 때까지 레이스와 블록을 잃습니다.

cctor가 완료 될 때까지 손실 스레드가 차단 됩니까? 정말 ?

정말.

그렇다면 승리 한 스레드 의 cctor가 이전에 손실 된 스레드가 가져온 잠금을 차단하는 코드를 호출하면 어떻게 될까요?

그런 다음 고전적인 잠금 순서 반전 조건이 있습니다. 프로그램 교착 상태. 영원히.

위험 해 보입니다. 교착 상태를 어떻게 피할 수 있습니까?

그렇게 할 때 아프면 그만두십시오 . cctor에서 차단할 수있는 일은 절대하지 마십시오.

복잡한 보안 요구 사항을 적용하기 위해 cctor 초기화 의미론에 의존하는 것이 좋은 생각입니까? 그리고 사용자 상호 작용을 수행하는 cctor를 갖는 것이 좋은 생각입니까?

좋은 아이디어도 아닙니다. 제 조언은 방법의 보안에 영향을 미치는 전제 조건이 충족되도록 다른 방법을 찾아야한다는 것입니다.


답변

MSDN 에 따르면 정적 생성자 :

정적 생성자는 첫 번째 인스턴스가 생성되거나 정적 멤버가 참조되기 전에 클래스를 초기화하기 위해 자동으로 호출됩니다.

정적 방법은 전에 정적 생성자가 호출됩니다 그래서 MyClass.MyMethod()호출 (없는 가정 정적 건설 또는 물론 정적 필드 초기화 중에 호출).

이제 비동기식으로 static constructor작업하는 경우 동기화하는 것이 귀하의 작업입니다.


답변

# 3은 실제로 # 1입니다. 정적 초기화는 자신이 속한 클래스를 처음 사용할 때까지 시작되지 않습니다.

MyMethod정적 생성자 또는 정적 초기화 블록에서를 호출 하면 가능합니다 . MyMethod정적 생성자에서 직접 또는 간접적으로 호출하지 않아도 괜찮습니다.


답변

로부터 문서 (강조 광산) :

정적 생성자는 첫 번째 인스턴스 가 생성 되거나 정적 멤버가 참조 되기 전에 클래스를 초기화 하기 위해 자동으로 호출됩니다
.


답변

정적 메서드에서 클래스의 인스턴스를 만들지 않은 경우 4는 항상 2 다음에 올 것이라고 보장 할 수 있지만 1과 3의 경우는 동일하지 않습니다.


답변

mymethod가 실행되기 전에 정적 생성자가 호출됩니다. 그러나 2 전에 4가 호출되면 망가 졌다면 디자인을 다시 생각하는 것이 좋습니다. 어쨌든 정적 생성자에서 복잡한 작업을 수행해서는 안됩니다.


답변

CLR은 정적 멤버에 액세스하기 전에 정적 생성자가 실행되도록 보장합니다. 그러나 디자인이 약간 냄새가납니다. 다음과 같이하는 것이 더 간단합니다.

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

디자인에서 인증이 실패하면 MyMethod가 실행되지 않도록하는 유일한 방법은 예외를 발생시키는 것입니다.