답변:
클래스 내에서 (숨겨진) 변수를 null로 설정할 수 있습니다. null 참조는 효과적으로 빈 호출 목록을 나타내는 일반적인 방법입니다.
클래스 외부에서는이 작업을 수행 할 수 없습니다. 이벤트에는 기본적으로 "구독"과 "구독 취소"가 표시됩니다.
필드와 유사한 이벤트가 실제로 수행하는 작업을 인식하는 것이 좋습니다. 변수 와 이벤트를 동시에 만듭니다. 클래스 내에서 변수를 참조하게됩니다. 외부에서는 이벤트를 참조합니다.
자세한 내용은 이벤트 및 대리인에 대한 내 기사 를 참조하십시오.
EventHandlerList
, 당신은 할 수 있습니다. 그래도이 두 가지 경우를 인식해야합니다. 다른 구현도있을 수 있습니다.
hidden
.
class c1
{
event EventHandler someEvent;
ResetSubscriptions() => someEvent = delegate { };
}
null ref 예외를 피하는 delegate { }
것보다 사용하는 것이 좋습니다 null
.
List.Clear()
vs를 사용하는 것과 같습니다 myList = null
.
모든 구독자를 지우는 가장 좋은 방법은이 기능을 외부에 노출하려는 경우 다른 공용 메소드를 추가하여 someEvent를 null로 설정하는 것입니다. 이것은 보이지 않는 결과가 없습니다. 전제 조건은 키워드 'event'를 사용하여 SomeEvent를 선언하는 것입니다.
요컨대, 125 페이지, 책 C # 4.0을 참조하십시오.
여기서 일부는 Delegate.RemoveAll
방법 사용을 제안했습니다 . 사용하면 샘플 코드가 아래 양식을 따를 수 있습니다. 그러나 정말 바보입니다. 왜 함수 SomeEvent=null
내부에 있지 ClearSubscribers()
않습니까?
public void ClearSubscribers ()
{
SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);
// Then you will find SomeEvent is set to null.
}
개념적 확장 된 지루한 의견.
"event"또는 "delegate"대신 "event handler"라는 단어를 사용합니다. 그리고 다른 것들에 "이벤트"라는 단어를 사용했습니다. 일부 프로그래밍 언어 (VB.NET, Object Pascal, Objective-C)에서 "이벤트"는 "메시지"또는 "신호"라고하며 "메시지"키워드와 특정 설탕 구문이 있습니다.
const
WM_Paint = 998; // <-- "question" can be done by several talkers
WM_Clear = 546;
type
MyWindowClass = class(Window)
procedure NotEventHandlerMethod_1;
procedure NotEventHandlerMethod_17;
procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
procedure DoClearEventHandler; message WM_Clear;
end;
또한 "메시지"에 응답하기 위해 "대리인"은 단일 대리인이든 여러 대리인이든 응답합니다.
요약 : "이벤트"는 "질문", "이벤트 핸들러"는 답입니다.
이것은 내 솔루션입니다.
public class Foo : IDisposable
{
private event EventHandler _statusChanged;
public event EventHandler StatusChanged
{
add
{
_statusChanged += value;
}
remove
{
_statusChanged -= value;
}
}
public void Dispose()
{
_statusChanged = null;
}
}
모든 호출 목록 멤버를 등록 해제 Dispose()
하려면 using(new Foo()){/*...*/}
패턴 을 호출 하거나 사용해야 합니다.
Delegate[] dary = TermCheckScore.GetInvocationList();
if ( dary != null )
{
foreach ( Delegate del in dary )
{
TermCheckScore -= ( Action ) del;
}
}
GetInvocationList
.
콜백을 수동으로 추가 및 제거하는 대신 여러 곳에서 여러 델리게이트 유형을 선언하는 대신 :
// The hard way
public delegate void ObjectCallback(ObjectType broadcaster);
public class Object
{
public event ObjectCallback m_ObjectCallback;
void SetupListener()
{
ObjectCallback callback = null;
callback = (ObjectType broadcaster) =>
{
// one time logic here
broadcaster.m_ObjectCallback -= callback;
};
m_ObjectCallback += callback;
}
void BroadcastEvent()
{
m_ObjectCallback?.Invoke(this);
}
}
이 일반적인 접근 방식을 시도해 볼 수 있습니다.
public class Object
{
public Broadcast<Object> m_EventToBroadcast = new Broadcast<Object>();
void SetupListener()
{
m_EventToBroadcast.SubscribeOnce((ObjectType broadcaster) => {
// one time logic here
});
}
~Object()
{
m_EventToBroadcast.Dispose();
m_EventToBroadcast = null;
}
void BroadcastEvent()
{
m_EventToBroadcast.Broadcast(this);
}
}
public delegate void ObjectDelegate<T>(T broadcaster);
public class Broadcast<T> : IDisposable
{
private event ObjectDelegate<T> m_Event;
private List<ObjectDelegate<T>> m_SingleSubscribers = new List<ObjectDelegate<T>>();
~Broadcast()
{
Dispose();
}
public void Dispose()
{
Clear();
System.GC.SuppressFinalize(this);
}
public void Clear()
{
m_SingleSubscribers.Clear();
m_Event = delegate { };
}
// add a one shot to this delegate that is removed after first broadcast
public void SubscribeOnce(ObjectDelegate<T> del)
{
m_Event += del;
m_SingleSubscribers.Add(del);
}
// add a recurring delegate that gets called each time
public void Subscribe(ObjectDelegate<T> del)
{
m_Event += del;
}
public void Unsubscribe(ObjectDelegate<T> del)
{
m_Event -= del;
}
public void Broadcast(T broadcaster)
{
m_Event?.Invoke(broadcaster);
for (int i = 0; i < m_SingleSubscribers.Count; ++i)
{
Unsubscribe(m_SingleSubscribers[i]);
}
m_SingleSubscribers.Clear();
}
}