최신 정보
C # 6 부터이 질문에 대한 답변은 다음과 같습니다.
SomeEvent?.Invoke(this, e);
다음과 같은 조언을 자주 듣거나 읽습니다.
이벤트를 확인하고 시작하기 전에 항상 이벤트 사본을 만드 null
십시오. 이렇게하면 null
null을 확인하는 위치 와 이벤트 를 발생시키는 위치 사이에 이벤트가 발생하는 스레딩 관련 잠재적 문제가 제거됩니다 .
// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
업데이트 : 이벤트 멤버가 일시적이어야 할 수 있다는 최적화에 대해 읽었지만 Jon Skeet은 CLR이 복사본을 최적화하지 않는다고 대답했습니다.
그러나이 문제가 발생하기 위해서는 다른 스레드가 다음과 같은 작업을 수행해야합니다.
// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;
// Good, now we can be certain that OnTheEvent will not run...
실제 순서는 다음과 같습니다.
// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;
// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;
// Good, now we can be certain that OnTheEvent will not run...
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
OnTheEvent
저자가 구독을 취소 한 후에 실행 되는 요점은 이러한 일이 발생하지 않도록 특별히 구독을 취소 한 것입니다. 실제로 필요한 것은 접근 자 add
와 remove
접근 자 에서 적절한 동기화를 통해 사용자 정의 이벤트 구현입니다 . 또한 이벤트가 발생하는 동안 잠금이 유지되면 교착 상태가 발생할 수 있습니다.
그래서이있다 화물 숭배 프로그래밍 ? 그런 식으로 보입니다-많은 사람들이 여러 스레드로부터 코드를 보호하기 위해이 단계를 수행해야합니다. 실제로 이벤트가 멀티 스레드 디자인의 일부로 사용되기 전에 이것보다 훨씬 더주의를 기울여야 할 것 같습니다 . 따라서 추가 관리를하지 않는 사람들은이 조언을 무시할 수도 있습니다. 단일 스레드 프로그램에서는 문제가되지 않으며 실제로 volatile
대부분의 온라인 예제 코드가없는 경우에는 조언이 없을 수도 있습니다. 전혀 효과.
(그리고 delegate { }
멤버 선언에 빈 것을 할당하는 것이 훨씬 간단하지 않으므로 null
처음 부터 확인할 필요가 없습니다 .)
업데이트 :명확하지 않은 경우 모든 상황에서 null 참조 예외를 피하기 위해 조언의 의도를 파악했습니다. 내 요점은이 특정 null 참조 예외가 다른 스레드가 이벤트에서 delisting하는 경우에만 발생할 수 있으며 그 이유는 해당 기술을 통해 더 이상 호출이 수신되지 않도록하는 것입니다. . 경쟁 조건을 숨기고있을 것입니다. 공개하는 것이 좋습니다. 이 null 예외는 구성 요소의 남용을 감지하는 데 도움이됩니다. 구성 요소가 악용되지 않도록하려면 WPF의 예를 따르십시오. 스레드 ID를 생성자에 저장 한 다음 다른 스레드가 구성 요소와 직접 상호 작용하려고하면 예외를 throw 할 수 있습니다. 또는 진정한 스레드 안전 구성 요소를 구현하십시오 (쉬운 작업은 아님).
그래서 나는 단지이 카피 / 체크 관용구를하는 것은화물 컬트 프로그래밍이며, 코드에 혼란과 소음을 추가한다고 주장한다. 실제로 다른 스레드로부터 보호하려면 더 많은 작업이 필요합니다.
Eric Lippert의 블로그 게시물에 대한 답변으로 업데이트 :
따라서 이벤트 처리기에서 놓친 주요한 사항이 있습니다. "이벤트 처리기가 구독 취소 된 후에도 호출 될 때 이벤트 처리기가 강력해야합니다." 대리자 null
. 이벤트 핸들러에 대한 요구 사항이 어디에나 문서화되어 있습니까?
"이 문제를 해결하는 다른 방법이 있습니다. 예를 들어, 처리기가 초기화되지 않은 빈 동작을 갖도록 초기화하는 것입니다. 그러나 null 검사를 수행하는 것이 표준 패턴입니다."
그래서 내 질문의 나머지 조각은 왜 명시 적 null 검사가 "표준 패턴"입니까? 빈 델리게이트를 할당하는 대안 = delegate {}
은 이벤트 선언에 추가하기 만하면되며, 이렇게하면 이벤트가 발생하는 모든 장소에서 악의적 인 행사 더미가 제거됩니다. 빈 델리게이트가 인스턴스화하기에 저렴하다는 것을 쉽게 알 수 있습니다. 아니면 여전히 뭔가 빠졌습니까?
Jon Skeet이 제안한대로 2005 년에했던 것처럼 죽지 않은 .NET 1.x 조언 일 것입니다.
EventName(arguments)
가 널이 아닌 경우 델리게이트를 호출하지 않고 이벤트의 델리게이트를 무조건 호출 하기로 결정했다는 것입니다 (널이면 아무것도 수행하지 않음).