创建Messenger服务

时间:2015-03-26 10:40:38

标签: c# generics delegates action

为了帮助减少我的ViewModel之间的依赖关系,我正在尝试创建自己的Messenger服务。

以下是一些代码:

public struct Subscription
{
    public Type Type { get; set; }
    public string Message { get; set; }

    //Error: Cannot implicitly convert type 'System.Action<TPayload>' to 'System.Action'
    public Action Callback { get; set; }
}

public static class Messenger
{
    private static List<Subscription> Subscribers { get; set; }

    static Messenger()
    {
        Subscribers = new List<Subscription>();
    }

    public static void Subscribe<TPayload>(string message, Action<TPayload> callback)
    {
        //Add to the subscriber list
        Subscribers.Add(new Subscription()
            {
                Type = typeof(TPayload),
                Message = message,
                Callback = callback
            });
    }

    public static void Send<TPayload>(string message, TPayload payload)
    {
        //Get all subscribers that match the message and payload type
        IEnumerable<Subscription> subs = Subscribers.Where(x => x.Message == message && x.Type == typeof(TPayload));

        //Invoke the callback and send the payload.
        foreach (Subscription sub in subs)
            sub.Callback.Invoke(payload);
    }
}

这里到底发生了什么事情:

Messenger类负责接收对消息的订阅,订阅者必须指定他们将接收的预期有效负载的返回类型,以及他们订阅的消息字符串。

subscribe方法处理订阅,send方法将调用Callback属性并将有效负载发送给任何订阅者。

我遇到的问题是Action<T>是委托,没有基本继承。我不能简单地在Subscription结构中添加通用,因为这会使List<Subscription>成为List<Subscription<T>>,这将使事情变得棘手。

有一点需要注意的是,我将来也会允许订阅没有有效负载。我试图了解如何实现这一目标。

修改 使用Matt的代码,我已经根据我的要求进行了调整。如果有人有兴趣的话。

public interface ISubscriber
{
    string Message { get; set; }

    void InvokeMethod(object args);
}

public class Subscriber : ISubscriber
{
    public string Message { get; set; }
    public Action Callback { get; set; }

    public virtual void InvokeMethod(object args = null)
    {
        Callback.Invoke();
    }
}

public class Subscriber<T> : Subscriber
{
    new public Action<T> Callback { get; set; }

    public override void InvokeMethod(object payload)
    {
        if (!(payload is T))
            throw new ArgumentException(String.Concat("Payload is not of type: ", typeof(T).Name), "payload");

        Callback.Invoke((T)payload);
    }
}

public static class Messenger
{
    private static List<ISubscriber> Subscribers { get; set; }

    static Messenger()
    {
        Subscribers = new List<ISubscriber>();
    }

    public static void Subscribe(string message, Action callback)
    {
        //Add to the subscriber list
        Subscribers.Add(new Subscriber()
        {
            Message = message,
            Callback = callback
        });
    }

    public static void Subscribe<TPayload>(string message, Action<TPayload> callback)
    {
        //Add to the subscriber list
        Subscribers.Add(new Subscriber<TPayload>()
        {
            Message = message,
            Callback = callback
        });
    }

    public static void Send(string message)
    {
        //Invoke the Callback for all subscribers
        foreach (Subscriber sub in GetSubscribers(message))
            sub.InvokeMethod();
    }

    public static void Send<TPayload>(string message, TPayload payload)
    {
        //Invoke the TypedCallback for all subscribers
        foreach (ISubscriber sub in GetSubscribers(message))
            sub.InvokeMethod(payload);
    }

    private static IEnumerable<ISubscriber> GetSubscribers(string message)
    {
        //Get all subscribers by matching message.
        return Subscribers.Where(x => x.Message == message);
    }
}

1 个答案:

答案 0 :(得分:2)

解决此问题的最佳方法是使用带有通用方法的接口为您执行Action。

public interface ISubscription
{
    Type Type { get;}
    String Message { get; set; }
    void InvokeMethod(object args);
}


public class Subscription<T> : ISubscription
{
    public Type Type { get { return typeof(T); } }
    public string Message { get; set; }

    public Action<T> TypedCallback { get; set; }

    void ISubscription.InvokeMethod(object args)
    {
        if (!(args is T))
        {
            throw new ArgumentException(String.Concat("args is not type: ", typeof(T).Name), "args");
        }
        TypedCallback.Invoke((T)args);
    }
}

public static class Messenger
{
    private static List<ISubscription> Subscribers { get; set; }

    static Messenger()
    {
        Subscribers = new List<ISubscription>();
    }

    public static void Subscribe<TPayload>(string message, Action<TPayload> callback)
    {
        //Add to the subscriber list
        Subscribers.Add(new Subscription<TPayload>()
        {
            Message = message,
            TypedCallback = callback
        });
    }

    public static void Send<TPayload>(string message, TPayload payload)
    {
        //Get all subscribers that match the message and payload type
        IEnumerable<ISubscription> subs = Subscribers.Where(x => x.Message == message && x.Type == typeof(TPayload));

        foreach (ISubscription sub in subs)
            sub.InvokeMethod(payload);

    }
}

然后可以这样使用。

class Program
{
    static void Main(string[] args)
    {
        Action<String> StringAction = new Action<string>((a) => WriteString(a));
        Action<Int32> Int32Action = new Action<Int32>((a) => WriteString(a.ToString()));

        Messenger.Subscribe<String>("Sub1", StringAction);
        Messenger.Send<String>("Sub1", "I am a string");

        Messenger.Subscribe<Int32>("Sub2", Int32Action);
        Messenger.Send<Int32>("Sub2", 72);

        Console.ReadLine();
    }

    private static String WriteString(String message)
    {
        Console.WriteLine(message);
        return message;
    }

}