Last active
July 28, 2017 02:47
-
-
Save audinue/205973bf8f0cad2afc178e0c96db2534 to your computer and use it in GitHub Desktop.
Powerful message subscription system.
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
/// <summary> | |
/// Represents an abstract generic message. | |
/// </summary> | |
public abstract class Message<T> { | |
private readonly T content; | |
public Message(T content) { | |
this.content = content; | |
} | |
public T Content { | |
get { return content; } | |
} | |
} | |
/// <summary> | |
/// Represents a generic message subscriber that accepts a message of type T. | |
/// </summary> | |
public interface ISubscriber<T> where T : class { | |
void Receive(object publisher, T message); | |
} | |
/// <summary> | |
/// Represents a message publisher. | |
/// </summary> | |
public class Publisher { | |
private readonly Dictionary<Type, List<object>> subscriptions = new Dictionary<Type, List<object>>(); | |
/// <summary> | |
/// Initializes a new instance of Publisher class. | |
/// </summary> | |
public Publisher() { | |
} | |
private void Subscribe(Type type, object subscriber) { | |
List<object> subscription; | |
if (!subscriptions.TryGetValue(type, out subscription)) { | |
subscription = subscriptions[type] = new List<object>(); | |
} | |
subscription.Add(subscriber); | |
} | |
/// <summary> | |
/// Subscribes a subscriber to a type of message. | |
/// </summary> | |
public void Subscribe<T>(ISubscriber<T> subscriber) where T : class { | |
if (subscriber == null) { | |
throw new ArgumentNullException("subscriber"); | |
} | |
Subscribe(typeof(T), subscriber); | |
} | |
/// <summary> | |
/// Subscribes a subscriber to all types of message acceptable by the subscriber. | |
/// </summary> | |
public void Subscribe(object subscriber) { | |
if (subscriber == null) { | |
throw new ArgumentNullException("subscriber"); | |
} | |
var types = subscriber | |
.GetType() | |
.GetInterfaces() | |
.Where(type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ISubscriber<>)); | |
if (!types.Any()) { | |
throw new ArgumentException("Subscriber does not accept any messages types.", "subscriber"); | |
} | |
foreach (var type in types) { | |
Subscribe(type.GenericTypeArguments[0], subscriber); | |
} | |
} | |
/// <summary> | |
/// Unsubscribes a subscriber from a type of message. | |
/// </summary> | |
public void Unsubscribe<T>(ISubscriber<T> subscriber) where T : class { | |
if (subscriber == null) { | |
throw new ArgumentNullException("subscriber"); | |
} | |
List<object> subscription; | |
if (!subscriptions.TryGetValue(typeof(T), out subscription)) { | |
return; | |
} | |
subscription.Remove(subscriber); | |
} | |
/// <summary> | |
/// Unsubscribes a subscriber from all types of message. | |
/// </summary> | |
public void Unsubscribe(object subscriber) { | |
if (subscriber == null) { | |
throw new ArgumentNullException("subscriber"); | |
} | |
foreach (var subscription in subscriptions.Values) { | |
subscription.Remove(subscriber); | |
} | |
} | |
/// <summary> | |
/// Unsubscribes all subscribers. | |
/// </summary> | |
public void Unsubscribe() { | |
subscriptions.Clear(); | |
} | |
/// <summary> | |
/// Publishes a message of type T. | |
/// </summary> | |
public void Publish<T>(T message) where T : class { | |
if (message == null) { | |
throw new ArgumentNullException("message"); | |
} | |
List<object> subscription; | |
if (!subscriptions.TryGetValue(typeof(T), out subscription)) { | |
return; | |
} | |
foreach (ISubscriber<T> subscriber in subscription.ToArray()) { | |
subscriber.Receive(this, message); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment