2010-01-25 4 views
0

는이 코드가 .NET 일반 함께 작업 : 다음는 정적 및

public class EntityMapper<T> where T : IMappingStrategy, new() 
{ 
    private static T currentStrategy; 

    public static T CurrentStrategy 
    { 
     get 
     { 
      if (currentStrategy == null) 
       currentStrategy = new T(); 

      return currentStrategy; 
     } 
    } 


} 

:

public static void Main() 
    { 
     EntityMapper<ServerMappingStrategy>.CurrentStrategy.ToString(); 
     EntityMapper<ClientMappingStrategy>.CurrentStrategy.ToString(); 
     EntityMapper<ServerMappingStrategy>.CurrentStrategy.ToString(); 
    } 

글쎄, 질문은 :

내가 디버깅있을 때 내가 볼 수있는 이유 ServerBussinessMappingStrategy의 생성자는 한 번만 호출됩니다.

이 작업은 훌륭하지만, 필자는 항상 EntityMapper가 필요한 올바른 인스턴스를 반환하고 ServerMappingStrategy 클래스를 한 번만 인스턴스화합니다.

감사합니다.

PD : 죄송합니다 내 영어 jeje가)

답변

5

static 필드가 당신의 AppDomain의 기간 동안 지속되며, 처음 만들 때이 캐시 : 사실

public static T CurrentStrategy 
{ 
    get 
    { 
     if (currentStrategy == null) // <====== first use detected 
      currentStrategy = new T(); // <==== so create new and cache it 

     return currentStrategy; // <=========== return cached value 
    } 
} 

, 가장자리 경우가 있습니다 두 번 (또는 그 이상) 실행할 수 있지만 가능성은 희박합니다.

이것은 지연된 초기화에 대한 꽤 일반적인 패턴이며 BCL의 여러 위치에서 거의 동일하게 사용됩니다. 을 한 번에 번 수행해야하는 경우 동기화 (lock 등) 또는 정적 초기화 프로그램이있는 중첩 클래스와 같은 것이 필요합니다.

+0

동기 문제는 선언에서 초기화하는 것이 가장 좋은 방법입니다. Jon Skeet은 여기에 더 자세히 설명되어 있습니다. http://www.yoda.arachsys.com/csharp/singleton.html –

1

일반적으로 한 번만 호출됩니다. 그것은 당신이 경쟁 조건을 가지고 있지 않다면 말입니다.

의 두 개의 스레드가이 문장을 동시에 실행한다고 가정 해 봅시다 :

EntityMapper<ServerMappingStrategy>.CurrentStrategy.ToString(); 

의 Windows가 갑자기 다음 스레드 B로 제어 할 때 스레드currentStrategy == null까지 실행되지만 new T() 전에 일시 정지됩니다 가정 해 봅시다 비교를 다시 수행하면 currentStrategy은 여전히 ​​null이며 생성자를 호출하고 currentStrategy에 새 인스턴스를 할당합니다. 그런 다음 어떤 시점에서 Windows는 다시 스레드 A으로 제어를 다시 보내서 생성자를 다시 호출합니다. 일반적으로 정적 멤버는 스레드 안전성이 있다고 기대되기 때문에 중요합니다. 그래서 내가 너라면, 그 비트를 lock 절로 감쌀 것이다.

P. 이 스 니펫은 T가 널이 될 수없는 구조체 일 수 있으므로 컴파일되지 않습니다. null과 비교하는 대신 default (T)와 비교하거나 T가 클래스 여야한다고 지정하십시오.