2012-02-18 3 views
3

안녕하세요, 이것은 나에게 잘못되었습니다. 이것이 설계된 방식입니까?왜 autofac은 일회용으로 두 번 처분합니까?

내 일회용 클래스 :

class C : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("Disposing C"); 
    } 
} 

등록 :

cb.RegisterInstance(new C()); 

사용법 :

using (IContainer container = BuildContainer()) 
{ 
    var c = container.Resolve<C>(); 
    Console.WriteLine("C resolved"); 
} 

출력 :

C resolved 
Disposing C 
Disposing C 
,

동일한 객체에서 Dispose를 여러 번 호출하는 것은 좋지 않을 것이라고 생각합니다.

참고 :이

cb.Register(c => new C()); 

같은 클래스를 등록 할 때 그것은 단지 한 번에 배치됩니다. 차이점은 무엇입니까?

+0

몇 개의 C 인스턴스가 있습니까? WriteLine을 생성자 안에 넣을 수도 있습니다. –

+0

필자는 Autofaq에 익숙하지 않지만 인스턴스를 등록하는 것과 공장을 등록하는 것 사이에 차이가있는 것처럼 보입니다. 첫 번째 예에서 Autofaq가 등록 된 "구성 요소"를 처분하는 방식으로 인해 인스턴스가 두 번 배치 될 수 있습니다. Autofaq 컨테이너 자체가있을 때 등록 된 "서비스"또는 해결 자 (이 경우 인스턴스 자체)를 삭제하는 Autofaq로 인해 처분됩니다. 폐기. –

+0

인스턴스가 하나뿐입니다. – Kugel

답변

12

같은 개체에 여러 번 Dispose를 호출하는 것이 좋지 않을까 생각합니다.

아니요, Dispose은 여러 번 호출하는 것이 안전해야합니다. 이 문서의 내용 : "The object must not throw an exception if its Dispose method is called multiple times." 안전해야하기 때문에 한 번만 호출하는 다른 라이브러리에 의존해서는 안되며 여러 Dispose 호출을 발생시키지 않아도 안되는 변경 사항에는 아무런 문제가 없습니다.

+0

좋은 지적이지만 누군가가 무시할 수있는 조언 일뿐입니다. 게다가이 내 질문에 대답하지 않습니다. – Kugel

+0

hvd가 맞다면 주요 관심사는 C –

+3

의 깨진 구현에만 적용됩니다. 문서화 된 API를 무시한 @Kugel은 "잘못하고있다"라고 불리며 솔직히 IDisposable을 구현하는 사람의 버그를 나타냅니다. 나는 컨테이너가 단지 한번만 처분을 시도해야한다는 것에 동의하지 않는다. 그러나 선택에 따라 나는 매일 "처분되지 않는다"보다 "폐기 된 17 배"를 택할 것이다. –

2

Hvd가 맞습니다. Dispose 전화를 여러 번 허용하려면 일회용 수업을 준비해야합니다. 구성 요소 인 경우

Autofac 자동 평생 범위 동안 해결 각 구성 요소에 Dispose를 호출이 MSDN 또는 위로 원래의 질문에

CodeProject처럼 여러 위치에 설명 된대로 일회용 패턴을 구현하는 올바른 방법입니다 IDisposable (예를 들어 수명 범위는 컨테이너의 수명이지만 다른 수명 시간 범위 일 수 있습니다). 그래서 이것은 하나의 "Disposing C"입니다.

RegisterInstance으로 구성 요소를 등록한 경우 컨테이너를 처리 할 때 (해결되지 않은 경우에도!) Dispose이 호출됩니다. 이것은 두 번째 "Disposing C"입니다. 당신은 그래서 (이 "외부 적 소유"아니에요)을 추적 할 수 있습니다 Resolve를 호출 할 때

사용한
builder.RegisterInstance(new C()).ExternallyOwned(); 

cb.Register(c => new C()); 다음 Autofac 당신을위한 C 인스턴스를 생성합니다

이 추가 ExternallyOwned를 사용하여 해제 처분 설정할 수 있습니다 따라서 litetime 범위가 끝나면 Dispose 한 번만 호출됩니다.

Autofac의 Deterministic Disposal에 대한 자세한 내용을 볼 수 있습니다.

+0

나는 autofac이 모든 disposables를 소유하고 다르게 지정하지 않는 한 그것을 처분 함을 알고 있습니다. 방금 같은 인스턴스를 두 번 처리하지 않도록주의 할 것이라고 생각했습니다. – Kugel

+0

명백히 Autofac은주의를 기울이지 않습니다. 명시된 바와 같이 여러 번 Dispos를 호출하는 것이 문제가 아니기 때문입니다. – nemesv

0

Dispose 패턴은 잘못하기 쉽습니다. 잠재적으로 두 단계로 생각해야합니다.

  1. 할당 된 관리되지 않는 리소스를 지우는 중입니다. (예 : 메모리 해제 또는 종료 기능 호출)
  2. 관리되는 리소스를 모두 지우고 있습니다.

가장 일반적인 방법은 a double dispose pattern입니다. 당신의 종료 코드를 필요로하는 경우

public class MyClass : IDisposable { 
    private bool _disposed = false; 
    public void Dispose(){ 
     Dispose(true); 
     GC.SuppressFinalize(this); // stop the GC clearing us up, 
    } 
    protected virtual Dispose(bool disposing){ 
     if (!_disposed){ 
      if (disposing){ 
       // someone called Dispose() 

       // dispose any other IDispose objects we have 
      } 
      _disposed = true; 
     } 
    } 
} 

, 당신은 폐기 (BOOL) 메소드의 내용을 주위에 잠금을 넣어해야 할 수도 있습니다.

5

AutoFac 소스 코드를 살펴보면이 두 가지 원인을 알 수 있습니다.

RegisterInstance 확장 메서드는 제공된 인스턴스 (이 경우 c)를 ProvidedInstanceActivator에 랩핑하고이를 활성화 자 컬렉션에 유지합니다. 건축업자가 처분 될 때 저장된 액티베이터는 처분되고 포함 된 물체도 처분됩니다 (IDisposable을 지원한다고 가정).

해결 된 객체 (Resolve를 통해)는 또한 LifetimeScope 컨테이너에서 추적되며 빌더가 폐기 될 때 해당 객체도 처분됩니다.

해결 된 개체가 원래 제공된 인스턴스인지 여부를 AutoFac에서 확인하지 않기 때문에이 두 가지 처리는이 등록 스타일에서만 발생합니다.

이것은 사용자의 관점에 따라 버그 일 수도 있고 아닐 수도 있지만 일회용 개체가 @hvd에 언급 된 것처럼 올바르게 작성되면 무해합니다.