c# - 尝试设计一个小型消息处理程序类来模拟 C# 事件。这种方法有什么缺点?

标签 c# generics delegates messaging

这是我的代码:

static class MessageHandler<T> where T : Message
{
    public delegate void MessageDelegate(T m);

    private static MessageDelegate messageHandlers;

    public static void Publish(T message)
    {
        messageHandlers(message);
    }

    public static void Subscribe(MessageDelegate messageHandler)
    {
        messageHandlers += messageHandler;
    }
}

Message只是一个其他类可以继承的空类。大多数Message派生是具有相关属性的简单对象(这是针对游戏的,因此可能有一个 PlayerDamagedMessage,其属性为损坏和袭击者。)

基本上,在 Player当他们受到攻击时,他们会发布一个PlayerDamagedMessage然后其他想要了解的类可以订阅,然后在它发生时接收相关详细信息。

这适用于多个消息的原因是因为通用类在 C# 中的工作方式。我的意思是,在幕后使用的每个不同泛型类型都会有一个委托(delegate)副本。

实际上,我在玩游戏时偶然发现了这一点,我很兴奋,因为它确实简化了我的代码,并且在这一点上看起来几乎像一种设计模式。

我在这里发帖询问使用这种方法的潜在缺点。封面下的通用委托(delegate)数量是否有限制?像这样的规模会有多好?

此外,有没有什么方法可以进行某种泛型类型推断,从而使语句不必这么长?

MessageHandler<MessagePlayerDamaged>.Publish(new MessagePlayerDamaged(this, this));

最佳答案

我实际上使用了非常相似的模式并取得了很大的成功。我采取的进一步措施是将实际的消息处理程序封装在 MessageHandlerRegistry 中,以允许更清晰的语法。这是您修改的示例:

Message.cs

public class Message
{

}

MessageHandler.cs

public class MessageHandler<T> where T : Message
{
    private Action<T> messageHandlers;

    public void Publish(T message)
    {
        messageHandlers(message);
    }

    public void Subscribe(Action<T> messageHandler)
    {
        messageHandlers = (Action<T>) Delegate.Combine(messageHandlers, messageHandler);
    }
}

MessageHandlerRegistry.cs

public static class MessageHandlerRegistry
{
    private static readonly IDictionary<Type, object> _handlers = new Dictionary<Type, object>();

    public static void Publish<T>(T m) where T : Message
    {
        if (_handlers.ContainsKey(typeof (T)))
        {
            ((MessageHandler<T>) _handlers[typeof (T)]).Publish(m);
        }
    }

    public static void Subscribe<T>(Action<T> messageHandler) where T : Message
    {
        if (!_handlers.ContainsKey(typeof (T)))
        {
            _handlers[typeof (T)] = new MessageHandler<T>();
        }
        ((MessageHandler<T>) _handlers[typeof (T)]).Subscribe(messageHandler);
    }
}

Program.cs

class Program
{
    static void Main(string[] args)
    {
        MessageHandlerRegistry.Subscribe((Message m) => Console.WriteLine("Message received."));
        MessageHandlerRegistry.Publish(new Message());
    }
}

我看到的唯一缺点是过度松散耦合,在某些情况下使用传统的基于事件的方法更有意义,有时只发布一条消息更容易。

关于c# - 尝试设计一个小型消息处理程序类来模拟 C# 事件。这种方法有什么缺点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13558422/

相关文章:

c# - "Remember password"选项 [C#]

c# - string overload + operator 在哪里进行字符串连接?

c# - 使用长时间运行的构造函数设计对象

java - Java 中 String 列表和 String[] 列表,或 T 列表和 T[] 列表的通用方法

java - 创建用于验证的通用枚举包装器

c# - C# 中的++ 操作是原子的吗?

java - Java 获取一系列值的方法

Objective-c 用它的后代类型覆盖委托(delegate)

ios - 实例方法 'mapView(_:didFailToLocateUserWithError:)'几乎符合可选要求

ios - 在 View Controller 和类之间进行委托(delegate)