2009-03-04 8 views
4

그래서 나는 내가 규칙 의 확고한 교수입니다 고정/다른 프로그래머의 코드를 유지 (BLECH)설정/닷넷에서 이벤트 핸들러를 제거

붙어 있어요 "그것을 해결하지 말아 부러되지 않으면!" depsite가 무서운 코드를 발견 할 때마다 무언가를 바꿀 수 있기를 바란다. 필자는 코드의 절대 최소량 만 수정하여 필요한 수정을 할 수 있도록 제한하고있다. 그러나 어떤 경우에는 그것을 따르거나 변경하기 전에 뭔가를 이해해야합니다.

는 여기이 조금 건너 온 :

region.LineSelected = (x) => { }; 

그리고이 같은인지 궁금 :

첫 번째 줄이 무엇을하고 있는지 나는 100 % 긍정적하려는
region.LineSelected = null; 

전에 내가 가지고있는 방법을 바꾸려고 간다.

답변

8

주제에 관한 나의 의견을 기반으로 편집

그들은 동일하지 않습니다. 람다 버전은 빈 익명 메소드에 이벤트 핸들러를 추가합니다. 이것에 의해, 다른 코드가, 그것이 null인지 (즉, 리스너를 가지지 않는) 걱정하지 않고, LineSelected()를 자유롭게 기르도록 할 수 있습니다.

예 : 이벤트가 발생한다면 이전 후 뭔가 다른 스레드에서 LineSelected에서 구독이 취소 경우

var lineSelected = this.LineSelected; 

if (lineSelected != null) 
{ 
    lineSelected(EventArgs.Empty); 
} 

위의 문은 NullReferenceException이 던질 수 있습니다. LineSelected를 임시 변수에 할당 한 다음 올리면 구독 취소 된 이벤트 리스너를 호출 할 수 있습니다. null 대리자를 처리 할 때 권장되는 방법은 이벤트 처리기를 로컬 변수에 할당하는 것입니다.

빈 대리자를 추가하면 NullReferenceException에 대한 걱정없이 다른 코드에서 항상 LineSelected를 호출 할 수 있습니다. 로컬 변수에 멀티 캐스트 이벤트 대리자를 할당하면 다른 스레드가 값을 수정할 수 없음을 확신 할 수 있습니다.

+0

조금 더 설명 할 수 있습니까? –

+0

오케이, 편집 해 주셔서 감사합니다. –

+0

도움이 된 것을 기쁘게 생각합니다. –

1

아니요 동일한 것은 아닙니다. 첫 번째 줄은 LineSelectednull과 다른 매우 큰 대표자를 할당합니다.

차이점을 찾는 가장 쉬운 방법은 람다 구문을 사용할 때 컴파일러가 생성하는 코드를 보는 것입니다. 이 코드 :

using System; 

class Program 
{ 
    static void Main() 
    { 
     Action<int> func0 = (x) => { }; 
     Action<int> func1 = null; 
    } 
} 

정말이로 컴파일 : 컴파일러가 null로 설정하고 다른 곳에서 참조되지 않은으로 func1을 제거 할만큼 똑똑했다

internal class Program 
{ 
    // Methods 
    private static void Main() 
    { 
     Action<int> func0 = delegate (int x) { 
     }; 
    } 
} 

알 수 있습니다. 그러나 func0이 아직 남아 있고 아무 것도하지 않지만 위임자로 설정되어 있지만 null과 매우 다릅니다.

+0

어떻게 그렇게? 프로그래머가 이벤트 처리기를 제거하려는 의도가있을 때 왜 다른 빈 메서드를 이벤트에 할당할까요? –

2

첫 번째 코드 줄을 만들 이유가 없다고 생각합니다. 내가 생각할 수있는 유일한 것은 LineSelected 이벤트를 발생시킬 때 클래스의 첫 번째 코드 줄이있는 경우 LineSelected 이벤트가 null인지 확인하지 않아도된다는 것입니다.예 :

if (this.LineSelected != null) 
{ 
    LineSelected(this,new EventArgs()); 
} 

대신 null 확인없이 이벤트를 발생시킬 수 있습니다.

그러나 두 번째 코드 줄에서는 null을 확인해야합니다.

1

이벤트 처리기가 설정되어 있기 때문에 같지 않습니다.

는 LineSelected을 노출하는 클래스에 잊었다 말할 수 있습니다 : 클래스는 LineSelected를 호출한다면

if(LineSelected != null) 
    LineSelected(...) 

아무도 그 때 NullReferenceException이

주를 던질 것, 듣고하지 않습니다 당신이 할 수있는 또한 경쟁 조건을 피하기 위해 (내부 지역) 수행하십시오 :

var event = LineSelected; 경우 (이벤트! = null이) 이벤트 (...이

1

나는이 모든 이벤트에 널 (null) 검사를 피하기 위해 기술을 생각합니다.

LineSelected 이벤트 모금 코드가 적절한 널 체크가없는 경우, 효과 핸들러가 추가 더 측, 다음 위의 코드가 있기 때문에, 아무도 이벤트에 핸들러를 추가하지 않는 경우에도, 잘 작동하지 않습니다 비어있는 경우, 그러나

region.LineSelected = null; 

/* no event handlers added to LineSelected */ 

class Region { 
    void OnLineSelected() { 
     // Null error! 
     LineSelected(); 
    } 
} 

: 다음이 예외가 발생합니다 빈 핸들러가 항상 첨부됩니다.

리처드와 앤드류가 말을 확장하기 위해 10
1

, 그것은 당신이 이벤트를 발생시킬 때 대리인을 가지고 있기 때문에, 당신은에서 (먼저 널 (null)을 검사 할 필요가 없습니다 것을 의미합니다

region.LineSelected = delegate {}; 

의 상당이다 작은 실적 히트 가격)

+1

흠, 대리인에 대한 인수가 없습니다, 정말 작동합니까? ;) – eglasius

2

그건 단순한 대리인입니다. (이벤트 핸들러는 + = 및 - =로 수정하여 이벤트를 첨부하고 분리해야합니다).

Deleted 속성을 빈 처리기로 설정하면 위임을 호출하기 전에 null 검사를 수행 할 필요가 없습니다 (다른 사용자가 null로 설정할 수 없다고 가정).

이렇게하면 호출 코드를 더 편리하게 만들 수 있지만 성능을 향상시키는 것으로 혼동해서는 안됩니다 (null을 확인할 필요성을 제거함). 일반적으로 델리게이트 메소드 호출의 오버 헤드는 널 체크의 오버 헤드보다 상당히 높습니다. 예를 들어, 델리게이트가 99.99 %의 "실제"구현을 가지고있는 경우) null 체크를 피하면 성능이 향상 될 수 있지만 성능상의 작은 차이가 충분히 중요 할 수있는 시나리오는 상상하기 어렵습니다. 그만한 가치가 있다면 더 효율적인 무언가를 위해 대리인 호출을 완전히 제거하지 않아도됩니다.

관련 문제