我有一个名为 IDataIO 的接口(interface):
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//.....more events,methods and properties
}
我还有多个实现这个接口(interface)的类,分别是UdpIO
、TcpIO
、SerialIO
。
现在,我有一个 IO
类,它允许我在不同的输入/输出硬件之间切换。此类的每个实例都有一个 CurrentIODevice
属性,可以是 SerialIO
、UdpIO
或 TcpIO
之一。分配此属性后,我将 1 个或多个处理程序附加到 DataReceivedEvent
,以便在收到传入数据时通知我的 GUI,以及需要通知的其他类。
public class IO
{
IDataIO CurrentIODevice;
public IO()
{
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
UdpIO udp = new UdpIO();
CurrentIODevice = serial;
}
}
我还有一个 IOManager
类,它包含多个 IO
对象。
public class IOManager
{
List<IO> Ports = new List<IO>();
public IOManager()
{
Ports.Add(new IO());
Ports.Add(new IO());
}
Ports[0].CurrentIODevice = serial;
Ports[0].CurrentIODevice.DataReceivedHandler += MyGuiUpdate;
Ports[0].CurrentIODevice.DataReceivedHandler += MyDataProcessing;
}
我关心的(这不是问题 atm)是我将如何在运行时在不同的 IDataIO 接口(interface)之间进行更改。
在运行时执行以下语句的效果是什么:
//i know this is illegal but just to demonstrate
IOManager.Ports[0].CurrentIODevice = tcp;
事件处理程序是否仍能正常工作(并且正确)?
我是否需要在分配 CurrentIODevice 之前取消分配事件,然后再重新分配处理程序?如果是这种情况,我可以看到这种方法变得非常困惑,所以如果有人有更好的方法来解决这个问题,我会洗耳恭听:)
最佳答案
不,您的处理程序将不起作用,因为它们附加到旧对象。接口(interface)提供...一个对象的接口(interface),将其视为一种契约,但它们本身并不是不同的对象。
如果您需要在接口(interface)的不同实现之间切换(在运行时)并保持所有处理程序正常工作,您必须对接口(interface)本身具有相同的对象引用,类似于 strategy pattern (或多或少)。
在您的情况下,例如,您可以在 DataIO
对象中实现 IDataIO
接口(interface)。它将公开一个属性(或一个方法,我认为它的意图更明确)以在该接口(interface)的不同实现(串行、TCP 或其他)之间切换。它将是唯一一个将事件处理程序附加到该接口(interface)的对象(当具体实现发生变化时它将删除处理程序)。该对象的用户将始终看到它,无论它使用的具体实现是什么。
例子
这是一个解释这个概念的小例子。通用接口(interface)是这样的:
interface IDataIO
{
void Write(byte[] data);
byte[] Read();
event EventHandler DataReceived;
}
这是IDataIO的具体实现,其他类直接只用这个类:
sealed class DataIO : IDataIO
{
public void SetChannel(IDataIO concreteChannel)
{
if (_concreteChannel != null)
_concreteChannel.DataReceived -= OnDataReceived;
_concreteChannel = concreteChannel;
_concreteChannel.DataReceived += OnDataReceived;
}
public void Write(byte[] data)
{
_concreteChannel.Write(data);
}
public byte[] Read()
{
return _concreteChannel.Read();
}
public event EventHandler DataReceived;
private IDataIO _concreteChannel;
private void OnDataReceived(object sender, EventArgs e)
{
EventHandler dataReceived = DataReceived;
if (dataReceived != null)
dataReceived(this, e);
}
}
最后是一些测试代码:
class Test
{
public Test()
{
_channel = new TcpIO();
_channel.DataReceived += OnDataReceived;
}
public void SetChannel(IDataIO channel)
{
_channel.SetChannel(channel);
// Nothing will change for this "user" of DataIO
// but now the channel used for transport will be
// the one defined here
}
private void OnDataReceived(object sender, EventArgs e)
{
// You can use this
byte[] data = ((IDataIO)sender).Read();
// Or this, the sender is always the concrete
// implementation that abstracts the strategy in use
data = _channel.Read();
}
private DataIO _channel;
}
关于c# - 事件处理程序和接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10614478/