-
Notifications
You must be signed in to change notification settings - Fork 0
/
mediator.cs
135 lines (110 loc) · 3.94 KB
/
mediator.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
using System;
using System.Collections.Generic;
namespace nimbus
{
public interface ISubscribeFor<in TMessage> { }
public interface ISubscribeFor<in TMessage, TResult> : ISubscribeFor<TMessage> { }
public interface IHandle<in TMessage> : ISubscribeFor<TMessage>
{
void Handle(TMessage message);
}
public interface IHandle<in TMessage, TResult> : ISubscribeFor<TMessage, TResult>
{
TResult Handle(TMessage message);
}
public interface IHandleResult<in TMessage, TResult> : ISubscribeFor<TMessage, TResult>
{
TResult Handle(TMessage message, TResult result);
}
public interface ISubscribeHandlers
{
void Subscribe<TMessage>(Func<ISubscribeFor<TMessage>[]> handlers);
void Subscribe<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers) where TResult : new();
void Subscribe<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers, Func<TResult> initializeResult);
void SubscribeScalar<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers);
}
public interface IMediator
{
void Send<TMessage>(TMessage message);
TResult Send<TMessage, TResult>(TMessage message);
}
public class Mediator : ISubscribeHandlers, IMediator
{
private readonly Dictionary<Type, Subscription> _subscriptions;
public void Subscribe<TMessage>(Func<ISubscribeFor<TMessage>[]> handlers)
{
SubscribeInternal(handlers, () => new ResultTypeNotSpecifiedInSubscription());
}
public void Subscribe<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers) where TResult : new()
{
SubscribeInternal(handlers, () => new TResult());
}
public void Subscribe<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers, Func<TResult> initializeResult)
{
SubscribeInternal(handlers, () => initializeResult());
}
public void SubscribeScalar<TMessage, TResult>(Func<ISubscribeFor<TMessage>[]> handlers)
{
SubscribeInternal(handlers, () => default(TResult));
}
private void SubscribeInternal<TMessage>(Func<ISubscribeFor<TMessage>[]> handlers, Func<dynamic> initializeResult)
{
_subscriptions.Add(typeof(TMessage), new Subscription(handlers, initializeResult));
}
public void Send<TMessage>(TMessage message)
{
Execute(message);
}
public TResult Send<TMessage, TResult>(TMessage message)
{
return Execute(message);
}
private dynamic Execute<TMessage>(TMessage message)
{
Subscription subscription;
if (!_subscriptions.TryGetValue(typeof(TMessage), out subscription))
throw new ApplicationException("No Handlers subscribed for " + typeof(TMessage).Name);
var handlers = subscription.CreateHandlers();
var result = subscription.InitializeResult();
/*
* Use dynamic dispatch instead of if statements
* If you get a RuntimeBinderException, more than likely you have
* mixed types for TResult in your subscribed handlers
* asked for a TResult in Send with a different type than in the subscription
*/
foreach (var handler in handlers)
{
result = Dispatch(handler, message, result);
}
return result;
}
private TResult Dispatch<TMessage, TResult>(IHandle<TMessage> handler, TMessage message, TResult result)
{
handler.Handle(message);
return result;
}
private TResult Dispatch<TMessage, TResult>(IHandle<TMessage, TResult> handler, TMessage message, TResult result)
{
return handler.Handle(message);
}
private TResult Dispatch<TMessage, TResult>(IHandleResult<TMessage, TResult> handler, TMessage message, TResult result)
{
return handler.Handle(message, result);
}
public Mediator()
{
_subscriptions = new Dictionary<Type, Subscription>();
}
class Subscription
{
public Subscription(Func<dynamic[]> createHandlers, Func<dynamic> initializeResult)
{
CreateHandlers = createHandlers;
InitializeResult = initializeResult;
}
public Func<dynamic[]> CreateHandlers { get; private set; }
public Func<dynamic> InitializeResult { get; private set; }
}
class ResultTypeNotSpecifiedInSubscription{ }
}
}