2011-01-08 4 views
3

개체가 GC.SuppressFinalize를 호출했는지 여부를 감지하는 방법이 있습니까?개체가 GC.SuppressFinalize를 호출했는지 여부를 감지 할 수 있습니까?

나는이 (명확성을 위해 생략 완전한 폐기 패턴)과 같은 보이는 개체가 다음 ownsResource 생성자 매개 변수가 다음 파이널 라이저는 아무 상관이 없습니다, false 경우

public class ResourceWrapper { 
    private readonly bool _ownsResource; 
    private readonly UnmanagedResource _resource; 

    public ResourceWrapper(UnmanagedResource resource, bool ownsResource) { 
     _resource = resource; 
     _ownsResource = ownsResource; 
     if (!ownsResource) 
      GC.SuppressFinalize(this); 
    } 
    ~ResourceWrapper() { 
     if (_ownsResource) 
      // clean up the unmanaged resource 
    } 
} 

을 - 그래서 합리적인 것처럼 보입니다 (약간 기발한 경우) GC.SuppressFinalize을 생성자에서 바로 호출하십시오. 그러나이 동작은 기발한 것이기 때문에 XML 문서 주석에 주석을 달아달라고 유혹됩니다. 주석을 달 것을 유혹받는다면 그것을위한 단위 테스트를 작성해야합니다.

그러나 System.GC에 방법을 가지고있는 동안 객체의 finalizability (SuppressFinalize, ReRegisterForFinalize)를 설정, 나는 어떤 방법 객체의 finalizability를 얻을 표시되지 않습니다. GC.SuppressFinalize가 Typemock을 사거나 My own CLR 호스트를 작성하지 않은 채 주어진 인스턴스에서 호출되었는지 여부를 쿼리하는 방법이 있습니까?

답변

3

개체가 리소스를 소유하지 않은 경우 종료가 억제되었다는 것을 확인하려면 최종 사용자가 리소스를 소유하고 있음을 주장 할 수 있습니까? 테스트는 GC.Collect와 GC.WaitForPendingFinalizers를 수행해야하지만 프로덕션 코드는 assert (프로덕션 빌드에서 생략 될 수 있음)를 제외하고는 아무 것도 추가로 가지지 않습니다. 어설 션과 함께 한 가지주의 할 점 : 객체 생성과 소유권 상태 설정 사이에 객체를 생성하는 스레드가 죽으면, finalizer가 부적절하게 실행될 수 있습니다.

그건 그렇다. 내가 말한 바에 따르면, 자원의 소유 또는 소유하지 않은 별도의 하위 유형 OwnedResourceWrapper 및 SharedResourceWrapper를 사용하여 추상 ResourceWrapper 유형을 갖는 것이 더 나은지 궁금하다. 그렇다면 자원을 소유하지 않는 하위 유형은 우선 파이널 라이저를 가질 필요가 없습니다. SharedResourceWrapper가 IDisposable을 no-op로 구현하는 것이 유용 할 수 있습니다.

+0

둘 다 좋은 생각이지만, 나는 두 번째를 좋아한다. "소유주"의 책임을 별도의 물건으로 옮겨라. –

+0

별도의 객체 유형을 사용하면 IMHO가 작동 할 때보다 깨끗하게 처리됩니다. 즉, 자원 작성 시점을 래퍼가 알고 있고 그 상태가 변경되지 않을 것입니다.하지만 좀 더 많은 코드가 필요할 수 있습니다. 두 기술을 모두 사용할 수있는 것은 분명 유용합니다. 위의 편집에서 언급했듯이 finalizers는 실행되기 전에 기본적으로 실행되도록 설정되어 있습니다. 조금 엉성한 것으로 보이지만 대부분의 시나리오에서는 문제가되지 않을 것입니다. – supercat

4

이것은 불가능합니다. GC는이 정보를 제공하지 않습니다. 그 이유는 객체가있을 수있는 두 가지 상태뿐 아니라 이미 완료 대기열에 있거나 이미 완료되었을 수 있기 때문입니다.

사용자 지정 CLR 호스트가 도움이되지 않습니다. 호스팅 인터페이스는 gc에 후크를 제공하지 않습니다. 파이널 라이저에서 이것을 확인함으로써 SuppressFinalize가 호출되었는지 여부를 확인할 수 있습니다. 그것을 기록하십시오 (빨리). 그 반대를 증명할 수는 없습니다.

Fwiw, .NET 프레임 클래스는이 작업을 수행하지 않으므로 어쨌든 finalizer가 실행됩니다.

+0

일부 BCL 클래스는 실제로 해당 생성자에서 SuppressFinalize를 수행합니다. SqlConnection (비록 내가 조건부로 그것을 보지 못했지만). –

2

도움이 될 수 있습니다 (reductio absurdum). 트릭은 파이널 라이저에서 일부 로그 (정적 상태 일 수 있음)를 수행하고 누군가 부재하는 경우 억제 도구를 호출했지만 여전히 확신 할 수는 없습니다.

유형 작성자 인 경우 작동합니다.

+0

나는 그것에 대해 생각했다. 또한 GC.Collect 및 GC.WaitForPendingFinalizers를 내 테스트에서 호출해야합니다. 그래도 가능합니다. 그러나 프로덕션 코드가 테스트 용으로 만 추가 작업을하는 것을 싫어합니다. –

+0

전혀 권장하지 않지만 여전히 해결책입니다. 어쩌면 당신은 다른 사람들로부터보다 신뢰할만한 해결책을 찾을 수 있습니다. – Xaqron

관련 문제