-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPubSubEvent.cs
149 lines (136 loc) · 6.9 KB
/
PubSubEvent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using Godot;
using System;
using System.Linq;
/// <summary>
/// Defines a class that manages publication and subscription to events.
/// </summary>
public class PubSubEvent : EventBase
{
/// <summary>
/// Subscribes a delegate to an event.
/// </summary>
/// <param name="action">The delegate that gets executed when the event is published.</param>
/// <param name="keepSubscriberReferenceAlive">When <see langword="true"/>, the <see cref="PubSubEvent"/> keeps a reference to the subscriber so it does not get garbage collected.</param>
/// <returns>A <see cref="SubscriptionToken"/> that uniquely identifies the added subscription.</returns>
/// <remarks>
/// If <paramref name="keepSubscriberReferenceAlive"/> is set to <see langword="false" />, <see cref="PubSubEvent"/> will maintain a <see cref="WeakReference"/> to the Target of the supplied <paramref name="action"/> delegate.
/// If not using a WeakReference (<paramref name="keepSubscriberReferenceAlive"/> is <see langword="true" />), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior.
/// <para/>
/// The PubSubEvent collection is thread-safe.
/// </remarks>
public virtual SubscriptionToken Subscribe(Action action, bool keepSubscriberReferenceAlive = true)
{
IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive);
EventSubscription subscription = new EventSubscription(actionReference);
return InternalSubscribe(subscription);
}
/// <summary>
/// Publishes the <see cref="PubSubEvent"/>.
/// </summary>
public virtual void Publish()
{
InternalPublish();
}
/// <summary>
/// Removes the first subscriber matching <see cref="Action"/> from the subscribers' list.
/// </summary>
/// <param name="subscriber">The <see cref="Action"/> used when subscribing to the event.</param>
public virtual void Unsubscribe(Action subscriber)
{
lock (Subscriptions)
{
IEventSubscription eventSubscription = Subscriptions.Cast<EventSubscription>().FirstOrDefault(evt => evt.Action == subscriber);
if (eventSubscription != null)
{
Subscriptions.Remove(eventSubscription);
}
}
}
/// <summary>
/// Returns <see langword="true"/> if there is a subscriber matching <see cref="Action"/>.
/// </summary>
/// <param name="subscriber">The <see cref="Action"/> used when subscribing to the event.</param>
/// <returns><see langword="true"/> if there is an <see cref="Action"/> that matches; otherwise <see langword="false"/>.</returns>
public virtual bool Contains(Action subscriber)
{
IEventSubscription eventSubscription;
lock (Subscriptions)
{
eventSubscription = Subscriptions.Cast<EventSubscription>().FirstOrDefault(evt => evt.Action == subscriber);
}
return eventSubscription != null;
}
}
/// <summary>
/// Defines a class that manages publication and subscription to events.
/// </summary>
/// <typeparam name="TPayload">The type of message that will be passed to the subscribers.</typeparam>
public class PubSubEvent<TPayload> : EventBase
{
/// <summary>
/// Subscribes a delegate to an event.
/// </summary>
/// <param name="action">The delegate that gets executed when the event is published.</param>
/// <param name="threadOption">Specifies on which thread to receive the delegate callback.</param>
/// <param name="keepSubscriberReferenceAlive">When <see langword="true"/>, the <see cref="PubSubEvent{TPayload}"/> keeps a reference to the subscriber so it does not get garbage collected.</param>
/// <param name="filter">Filter to evaluate if the subscriber should receive the event.</param>
/// <returns>A <see cref="SubscriptionToken"/> that uniquely identifies the added subscription.</returns>
/// <remarks>
/// If <paramref name="keepSubscriberReferenceAlive"/> is set to <see langword="false" />, <see cref="PubSubEvent{TPayload}"/> will maintain a <see cref="WeakReference"/> to the Target of the supplied <paramref name="action"/> delegate.
/// If not using a WeakReference (<paramref name="keepSubscriberReferenceAlive"/> is <see langword="true" />), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior.
///
/// The PubSubEvent collection is thread-safe.
/// </remarks>
public virtual SubscriptionToken Subscribe(Action<TPayload> action, bool keepSubscriberReferenceAlive = true, Predicate<TPayload> filter = null)
{
IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive);
IDelegateReference filterReference;
if (filter != null)
{
filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive);
}
else
{
filterReference = new DelegateReference(new Predicate<TPayload>(delegate { return true; }), true);
}
EventSubscription<TPayload> subscription = new EventSubscription<TPayload>(actionReference, filterReference);
return InternalSubscribe(subscription);
}
/// <summary>
/// Publishes the <see cref="PubSubEvent{TPayload}"/>.
/// </summary>
/// <param name="payload">Message to pass to the subscribers.</param>
public virtual void Publish(TPayload payload)
{
InternalPublish(payload);
}
/// <summary>
/// Removes the first subscriber matching <see cref="Action{TPayload}"/> from the subscribers' list.
/// </summary>
/// <param name="subscriber">The <see cref="Action{TPayload}"/> used when subscribing to the event.</param>
public virtual void Unsubscribe(Action<TPayload> subscriber)
{
lock (Subscriptions)
{
IEventSubscription eventSubscription = Subscriptions.Cast<EventSubscription<TPayload>>().FirstOrDefault(evt => evt.Action == subscriber);
if (eventSubscription != null)
{
Subscriptions.Remove(eventSubscription);
}
}
}
/// <summary>
/// Returns <see langword="true"/> if there is a subscriber matching <see cref="Action{TPayload}"/>.
/// </summary>
/// <param name="subscriber">The <see cref="Action{TPayload}"/> used when subscribing to the event.</param>
/// <returns><see langword="true"/> if there is an <see cref="Action{TPayload}"/> that matches; otherwise <see langword="false"/>.</returns>
public virtual bool Contains(Action<TPayload> subscriber)
{
IEventSubscription eventSubscription;
lock (Subscriptions)
{
eventSubscription = Subscriptions.Cast<EventSubscription<TPayload>>().FirstOrDefault(evt => evt.Action == subscriber);
}
return eventSubscription != null;
}
}