Created
April 22, 2012 23:19
-
-
Save Pondidum/2467463 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class EventDistributor | |
{ | |
private readonly Dictionary<Type, List<WeakReference>> _events; | |
private static readonly Object Padlock = new Object(); | |
public Distributor() | |
{ | |
_events = new Dictionary<Type, List<WeakReference>>(); | |
} | |
public void RegisterFor<TEvent>(Action<TEvent> handler) | |
{ | |
var type = typeof(TEvent); | |
List<WeakReference> recipients; | |
lock (Padlock) | |
{ | |
if (!_events.TryGetValue(type, out recipients)) | |
{ | |
recipients = new List<WeakReference>(); | |
_events[type] = recipients; | |
} | |
recipients.Add(new WeakReference(handler)); | |
} | |
} | |
public void UnRegisterFor<TEvent>(Action<TEvent> handler) | |
{ | |
var type = typeof(TEvent); | |
List<WeakReference> recipients; | |
if (_events.TryGetValue(type, out recipients)) | |
{ | |
lock (Padlock) | |
{ | |
recipients.RemoveAll(o => o.Target.GetHashCode() == handler.GetHashCode()); | |
} | |
} | |
} | |
public void Publish<TEvent>(TEvent @event) | |
{ | |
var type = typeof(TEvent); | |
List<WeakReference> recipients; | |
if (!_events.TryGetValue(type, out recipients)) | |
{ | |
return; | |
} | |
lock (Padlock) | |
{ | |
recipients.RemoveAll(wr => wr.IsAlive == false); | |
recipients.ForEach(wr => | |
{ | |
var handler = (Action<TEvent>)wr.Target; | |
handler.BeginInvoke(@event, handler.EndInvoke, null); | |
}); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[TestFixture] | |
public class EventDistributorTests | |
{ | |
[Test] | |
public void When_publishing_an_event_without_a_handler() | |
{ | |
var distributor = new EventDistributor(); | |
Assert.DoesNotThrow(() => distributor.Publish(new PersonSavedEvent())); | |
} | |
[Test] | |
public void When_publishing_an_event_with_a_handler() | |
{ | |
var wasCalled = false; | |
var distributor = new EventDistributor(); | |
distributor.RegisterFor<TestEvent>(e => wasCalled = true); | |
distributor.Publish(new TestEvent()); | |
Assert.IsTrue(wasCalled, "The target was not invoked."); | |
} | |
[Test] | |
public void When_publishing_an_event_and_un_registering() | |
{ | |
var callCount = 0; | |
var increment = new Action<TestEvent>(e => callCount++); | |
var distributor = new EventDistributor(); | |
distributor.RegisterFor<TestEvent>(increment); | |
distributor.Publish(new TestEvent()); | |
distributor.UnRegisterFor<TestEvent>(increment); | |
distributor.Publish(new TestEvent()); | |
Assert.AreEqual(1, callCount); | |
} | |
[Test] | |
public void When_the_handling_class_does_not_call_unregister() | |
{ | |
var count = 0; | |
var increment = new Action(() => count++); | |
var distributor = new EventDistributor(); | |
using (var l = new Listener(distributor, increment)) | |
{ | |
distributor.Publish(new PersonSavedEvent()); | |
} | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
GC.Collect(); | |
distributor.Publish(new PersonSavedEvent()); | |
Assert.AreEqual(1, count, "OnPersonSaved should have only been called 1 time, was actually {0}", count); | |
} | |
private class TestEvent { } | |
public class Listener : IDisposable | |
{ | |
private readonly Action _action; | |
public Listener(EventDistributor events, Action action) | |
{ | |
_action = action; | |
events.RegisterFor<PersonSavedEvent>(OnPersonSaved); | |
} | |
private void OnPersonSaved(PersonSavedEvent e) | |
{ | |
_action.Invoke(); | |
} | |
public void Dispose() | |
{ | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment