2011-02-22 3 views
11

내가 이렇게 보이는 코드가있는 경우 :로컬 변수의 익명 이벤트 처리기를 구독 취소해야합니까?

public void Foo() 
{ 
    Bar bar = new Bar(); 

    bar.SomeEvent += (sender, e) => 
    { 
     //Do something here 
    }; 

    bar.DoSomeOtherThingAndRaiseSomeEvent(); 
} 

이 방법은 범위의 부족, 또는 내가의 때문에 메모리 누수를 방지하기 위해 수동으로 이벤트 구독을 취소 할 때 수집 barSomeEvent에 대한 참조?

답변

18

상황에 관계없이 문제가 없습니다. 가입자게시자이 수집되는 것을 막지 않지만 그 반대가 발생할 수 있습니다. 어느

  • 람다로 표현 익명 방법 FooEvent에서 제거 될 때까지 예를 들어

    이 경우

    class Foo 
    { 
        public event EventHandler FooEvent; 
    
        void LeakMemory() 
        { 
         Bar bar = new Bar(); 
    
         bar.AttachEvent(this); 
        } 
    } 
    
    class Bar 
    { 
        void AttachEvent(Foo foo) 
        { 
         foo.FooEvent += (sender, e) => { }; 
        } 
    } 
    

    LeakMemory 이내 Bar 인스턴스 '는 수집 될 수 없다 호출 목록

  • 첨부 된 Foo의 인스턴스를 수집 할 수 있습니다.

이벤트 (일반 delegate 인스턴스에 비해 구문상의 설탕)가 호출 될 때 호출 할 대리자 목록에 보유하고 있으며, 각 대리자는 차례로 해당 개체에 대한 참조를 가지고 있기 때문에 연결되어 있습니다 (이 경우 Bar의 인스턴스).

여기서는 수령 자격에 대해서만 이야기합니다. 단지 자격이 있기 때문에 에 관해서는 아무 말도하지 않고 (또는 실제로는 인 경우 일 경우)은 수집됩니다. 단지 일 수 있고 일 수 있습니다.

+0

"약한 참조 이벤트"의 표준 양식/관용구가 있는가 : 람다는 "함수 리터럴"종류의 문자열 리터럴처럼 때문 평등을 결정할 때 그러나 문자열과는 달리 그들은 의미 비교되지입니까? –

+0

@pst : 불행히도, 아니오. 이것은 이전에 논의 된 것입니다 (더 일반적으로 참조 할 수있는 대리인의 일부인 참조를 고려하지 않음). 그러나 복잡성과 잠재적 인 함정으로 인해 구현되지 못했습니다. 마지막으로 살펴본 이후로 계획에 변경이 있었을 수도 있지만, 내가 알기 엔 상황이 서서 계속 될 것입니다. WeakReference 클래스를 사용하는 솔루션조차도 문제를 다른 유형으로 옮깁니다. –

1

음, 객체 bar IT는 bar 변수가 가 쓰레기 수집되는을 방지 할 수 없습니다 단지의 ... 자동으로 쓰레기를 즉시 수집하지 않습니다 의미합니다.

이벤트 핸들러는 가비지 수집에서 Bar 인스턴스를 방지 할 것이다 어느 비록 - "정상적인"문제는 이벤트 핸들러는 인스턴스를 사용하는 경우 가비지 (수집에서 이벤트의 가입자 유지된다 메서드를 사용하거나 익명 함수에서 "this"를 캡처합니다. 일반적으로 게시자가 가비지 수집에 영향을주지 않습니다. 게시자가 모든 구독자에 대한 참조를 유지해야한다는 점을 기억하십시오. 구독자는 나중에 구독을 취소하거나 나중에 다른 회원을 사용하기를 원하지 않는 한 구독 내용을 기억할 필요가 없습니다.

Bar의 인스턴스를 계속 유지한다고 가정하면 코드가 정상적이어야합니다.

1

위의 답변은 정확합니다. 나는 단지 쪽지를 만들고 싶었다. Delegate/lambda에 대한 다른 참조를 유지하면 처리기로 사용 된 익명의 대리자는 구독을 취소 할 수 있습니다.

public event EventHandler MyEvent; 

... 

//adds a reference to this named method in the context of the current instance 
MyEvent += Foo; 

//Adds a reference to this anonymous function literal to MyEvent 
MyEvent += (s,e) => Bar(); 

... 

//The named method of the current instance will be the same reference 
//as the named method. 
MyEvent -= Foo; 

//HOWEVER, even though this lambda is semantically equal to the anonymous handler, 
//it is a different function literal and therefore a different reference, 
//which will not match the anonymous handler. 
MyEvent -= (s,e) => Bar(); 

var hasNoHandlers = MyEvent == null; //false 

//To successfully unsubscribe a lambda, you have to keep a reference handy: 

EventHandler myHandler = (s,e) => Bar(); 

MyEvent += myHandler; 

... 

//the variable holds the same reference we added to the event earlier, 
//so THIS call will remove the handler. 
MyEvent -= myHandler; 
관련 문제