📅  最后修改于: 2023-12-03 14:52:58.522000             🧑  作者: Mango
在一个大型的程序中,通常会涉及多个类之间的交互,为了保证代码的可维护性和可扩展性,我们常常采用事件的方式来处理类之间的交互。但是如何在许多类上应用事件呢?下面,我们将介绍一些实用的方法。
在.NET中,我们可以通过委托来实现事件的发布和订阅。在多个类之间传递事件时,我们可以定义一个公共委托,并在需要订阅事件的类中注册该委托。当事件发生时,所有注册了该委托的对象都会收到通知。
public delegate void EventHandler(object sender, EventArgs e);
public class Publisher
{
public event EventHandler MyEvent;
public void RaiseMyEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
public class Subscriber1
{
public Subscriber1(Publisher publisher)
{
publisher.MyEvent += HandleMyEvent;
}
private void HandleMyEvent(object sender, EventArgs e)
{
Console.WriteLine("Subscriber1 handles the event.");
}
}
public class Subscriber2
{
public Subscriber2(Publisher publisher)
{
publisher.MyEvent += HandleMyEvent;
}
private void HandleMyEvent(object sender, EventArgs e)
{
Console.WriteLine("Subscriber2 handles the event.");
}
}
在上述代码中,我们定义了一个公共委托EventHandler
和一个Publisher
类,该类定义了一个名为MyEvent
的事件,并在RaiseMyEvent
方法中发布事件。同时,我们定义了两个订阅者类Subscriber1
和Subscriber2
,它们在构造函数中注册MyEvent
事件,并实现了事件处理方法HandleMyEvent
。
最后,我们就可以使用以下代码来验证事件的发布和订阅了:
Publisher publisher = new Publisher();
Subscriber1 subscriber1 = new Subscriber1(publisher);
Subscriber2 subscriber2 = new Subscriber2(publisher);
publisher.RaiseMyEvent(); // 输出 Subscriber1 handles the event. 和 Subscriber2 handles the event.
如果我们需要在运行时动态注册事件,可以使用反射来实现。在.NET中,我们可以使用EventInfo
类来获取类的事件信息,并使用Delegate.CreateDelegate
方法来动态创建委托并将其添加到事件的订阅列表中。
以下代码演示了如何使用反射动态注册事件:
public class Publisher
{
public event EventHandler MyEvent;
public void RaiseMyEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
public class Subscriber
{
public void HandleMyEvent(object sender, EventArgs e)
{
Console.WriteLine("Subscriber handles the event.");
}
}
// 动态注册事件
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
EventInfo eventInfo = publisher.GetType().GetEvent("MyEvent");
Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, subscriber, "HandleMyEvent");
eventInfo.AddEventHandler(publisher, handler);
// 触发事件
publisher.RaiseMyEvent(); // 输出 Subscriber handles the event.
如果我们的程序存在多个进程或多台机器,则需要将事件分发到各个进程或机器上。这时,我们可以使用消息队列来实现事件的分发。
消息队列的基本原理是,生产者将消息放入队列中,消费者从队列中获取消息并进行处理。在.NET中,我们可以使用System.Messaging
命名空间下的MessageQueue
类来实现消息队列。
以下代码演示了如何使用MessageQueue
来实现事件的分发:
public class MessagePublisher
{
private MessageQueue queue;
public MessagePublisher(string queueName)
{
if (!MessageQueue.Exists(queueName))
{
MessageQueue.Create(queueName);
}
this.queue = new MessageQueue(queueName);
}
public void Publish(string message)
{
this.queue.Send(message);
}
}
public class MessageSubscriber
{
private MessageQueue queue;
private bool stop;
public MessageSubscriber(string queueName)
{
if (!MessageQueue.Exists(queueName))
{
throw new Exception($"Queue {queueName} does not exist.");
}
this.queue = new MessageQueue(queueName);
this.queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
}
public void Subscribe()
{
this.stop = false;
while (!stop)
{
try
{
Message message = this.queue.Receive();
string content = (string)message.Body;
HandleMessage(content);
}
catch (MessageQueueException e)
{
if (e.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
// Ignore timeout and continue.
}
else
{
throw;
}
}
}
}
private void HandleMessage(string message)
{
Console.WriteLine($"Subscriber handles message {message}.");
}
public void Unsubscribe()
{
this.stop = true;
}
}
在上述代码中,我们定义了一个名为MessagePublisher
的类和一个名为MessageSubscriber
的类。其中,MessagePublisher
类负责将消息放入消息队列中,MessageSubscriber
类负责从消息队列中获取消息并进行处理。
可以使用以下代码来验证该方法是否可行:
string queueName = "event-queue";
MessagePublisher publisher = new MessagePublisher(queueName);
MessageSubscriber subscriber = new MessageSubscriber(queueName);
Task.Run(() => subscriber.Subscribe());
publisher.Publish("Hello, world!");
publisher.Publish("Goodbye, world!");
Thread.Sleep(1000);
subscriber.Unsubscribe();