我最终稍微适应了Dalstroem's solution。这帮助我解决了两个问题:-
问题 1:每个收件人只能在每个上下文中注册一条消息
解决方案 - 将类型作为字典键的一部分(如上面 Dima 所建议的那样)。
问题 2:我的 xUnit 测试始终失败
解决方案 - 将 Messenger 从单例中更改。相反,将信使注入 ViewModel。
此外,至关重要的是,将 Dictionary 更改为 非静态成员。否则你会在并行测试中遇到各种各样的问题。
适应的解决方案:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Application.Messaging
{
public class Messenger
{
private readonly ConcurrentDictionary<MessengerKey, object> RecipientDictionary = new ConcurrentDictionary<MessengerKey, object>();
public Messenger()
{
}
public void Register<T>(object recipient, Action<T> action)
{
Register(recipient, action, null);
}
public void Register<T>(object recipient, Action<T> action, object context)
{
var key = new MessengerKey(recipient, typeof(T), context);
RecipientDictionary.TryAdd(key, action);
}
public void Unregister<T>(object recipient, Action<T> action)
{
Unregister(recipient, action, null);
}
public void Unregister<T>(object recipient, Action<T> action, object context)
{
object removeAction;
var key = new MessengerKey(recipient, typeof(T), context);
RecipientDictionary.TryRemove(key, out removeAction);
}
public void UnregisterAll()
{
RecipientDictionary.Clear();
}
public void Send<T>(T message)
{
Send(message, null);
}
public void Send<T>(T message, object context)
{
IEnumerable<KeyValuePair<MessengerKey, object>> result;
if (context == null)
{
// Get all recipients where the context is null.
result = from r in RecipientDictionary where r.Key.Context == null select r;
}
else
{
// Get all recipients where the context is matching.
result = from r in RecipientDictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r;
}
foreach (var action in result.Select(x => x.Value).OfType<Action<T>>())
{
// Send the message to all recipients.
action(message);
}
}
protected class MessengerKey
{
public object Recipient { get; private set; }
public Type MessageType { get; private set; }
public object Context { get; private set; }
public MessengerKey(object recipient, Type messageType, object context)
{
Recipient = recipient;
MessageType = messageType;
Context = context;
}
protected bool Equals(MessengerKey other)
{
return Equals(Recipient, other.Recipient)
&& Equals(MessageType, other.MessageType)
&& Equals(Context, other.Context) ;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((MessengerKey)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397)
^ ((MessageType != null ? MessageType.GetHashCode() : 0) * 397)
^ (Context != null ? Context.GetHashCode() : 0);
}
}
}
}
}