귀하의 경우에는 모든 것이 좋습니다. 이벤트 핸들러 의 대상 을 라이브로 유지하는 이벤트 를 게시 하는 객체입니다 . 그래서 내가 가지고 있다면 :
publisher.SomeEvent += target.DoSomething;
그런 다음 publisher
참조가 target
있지만 반대는 아닙니다.
귀하의 경우 게시자는 가비지 수집 대상이 될 것이므로 (다른 참조가 없다고 가정) 이벤트 처리기 대상에 대한 참조가 있다는 사실은 관련이 없습니다.
까다로운 경우는 게시자가 수명이 길지만 구독자가 원하지 않는 경우 입니다. 이 경우 처리기를 구독 취소해야합니다. 예를 들어 대역폭 변경에 대한 비동기 알림을 구독 할 수있는 일부 데이터 전송 서비스가 있고 전송 서비스 개체가 오래 지속된다고 가정합니다. 이렇게하면 :
BandwidthUI ui = new BandwidthUI();
transferService.BandwidthChanged += ui.HandleBandwidthChange;
// Suppose this blocks until the transfer is complete
transferService.Transfer(source, destination);
// We now have to unsusbcribe from the event
transferService.BandwidthChanged -= ui.HandleBandwidthChange;
(실제로 이벤트 핸들러를 유출하지 않도록 finally 블록을 사용하고 싶을 것입니다.) 구독을 취소하지 않았다면는 BandwidthUI
최소한 전송 서비스만큼 오래 지속됩니다.
개인적으로 나는 거의 이것을 접하지 않습니다. 일반적으로 이벤트를 구독하는 경우 해당 이벤트의 대상은 최소한 게시자만큼 유지됩니다. 예를 들어 양식은 그 위에있는 버튼만큼 지속됩니다. 이 잠재적 인 문제에 대해 아는 것은 가치가 있지만 일부 사람들은 참조가 어느 방향으로 가는지 알지 못하기 때문에 필요하지 않을 때 걱정한다고 생각합니다.
편집 : 이것은 Jonathan Dickinson의 의견에 대답하는 것입니다. 첫째, 동등성 동작을 명확하게 제공하는 Delegate.Equals (object) 문서를 살펴보십시오 .
둘째, 구독 취소가 작동하는 것을 보여주는 짧지 만 완전한 프로그램이 있습니다.
using System;
public class Publisher
{
public event EventHandler Foo;
public void RaiseFoo()
{
Console.WriteLine("Raising Foo");
EventHandler handler = Foo;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
else
{
Console.WriteLine("No handlers");
}
}
}
public class Subscriber
{
public void FooHandler(object sender, EventArgs e)
{
Console.WriteLine("Subscriber.FooHandler()");
}
}
public class Test
{
static void Main()
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
publisher.Foo += subscriber.FooHandler;
publisher.RaiseFoo();
publisher.Foo -= subscriber.FooHandler;
publisher.RaiseFoo();
}
}
결과 :
Raising Foo
Subscriber.FooHandler()
Raising Foo
No handlers
(Mono 및 .NET 3.5SP1에서 테스트되었습니다.)
추가 편집 :
이는 구독자에 대한 참조가있는 동안 이벤트 게시자를 수집 할 수 있음을 증명하기위한 것입니다.
using System;
public class Publisher
{
~Publisher()
{
Console.WriteLine("~Publisher");
Console.WriteLine("Foo==null ? {0}", Foo == null);
}
public event EventHandler Foo;
}
public class Subscriber
{
~Subscriber()
{
Console.WriteLine("~Subscriber");
}
public void FooHandler(object sender, EventArgs e) {}
}
public class Test
{
static void Main()
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
publisher.Foo += subscriber.FooHandler;
Console.WriteLine("No more refs to publisher, "
+ "but subscriber is alive");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("End of Main method. Subscriber is about to "
+ "become eligible for collection");
GC.KeepAlive(subscriber);
}
}
결과 (.NET 3.5SP1에서, Mono는 여기에서 약간 이상하게 작동하는 것 같습니다. 나중에 살펴 보겠습니다) :
No more refs to publisher, but subscriber is alive
~Publisher
Foo==null ? False
End of Main method. Subscriber is about to become eligible for collection
~Subscriber