C# Each 类 一个串口读写或如何DeepCopy串口?

C# Each Classes Write and Receive by One SerialPort or How to DeepCopy SerialPort?

我有三个 class,main,serial,meter。

主要是在用户单击按钮时创建新的仪表实例并添加管理列表。

// main.cs
MeterPanel meter = new MeterPanel(meterid);
list_Meters.Add(meter);

并且每个仪表都有一个串行实例class并对其进行控制。

// meter.cs
SerialClass serialclass = new SerialClass();
...
serialclass.SetMeterID("00001");
serialclass.OpenSerial("COM12", 9600);

和串口class用于串口打开、关闭、读取、写入。

// SerialClass.cs
SerialPort serial = new SerialPort();
string meterid = "";
public bool OpenSerial(string port, int baud)
{
    ...
    serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
    serial.Open();
}

private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    ...
}

private void SerialWrite(string str)
{
    serial.Write(str);
}
public void SetMeterID(string meterid)
{
    this.meterid = meterid;
}

如果 meter 有自己的端口就可以正常工作。

但是我想让电表共用一个端口。 如果其仪表 ID 与数据包的仪表 ID 不匹配,则串行 class 不响应。

电表如何共享一个端口?

首先,我尝试在 main class 上打开串行,然后每个仪表 class 进行深度复制串行 class。

    public object DeepCopy(object obj)
    {
        if (ReferenceEquals(obj, null)) return null;

        Type type = obj.GetType();
        if (type.IsValueType || type == typeof(string))
            return obj;
        else if (type.IsArray)
        {
            var array = obj as Array;
            var arrayType = Type.GetType(type.FullName.Replace("[]", string.Empty));
            var arrayInstance = Array.CreateInstance(arrayType, array.Length);

            for (int i = 0; i < array.Length; i++)
                arrayInstance.SetValue(DeepCopy(array.GetValue(i)), i);
            return Convert.ChangeType(arrayInstance, type);
        }
        else if (type.IsClass)
        {
            var instance = Activator.CreateInstance(obj.GetType());
            var fields = type.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (var field in fields)
            {
                var fieldValue = field.GetValue(obj);
                if (ReferenceEquals(fieldValue, null)) continue;
                field.SetValue(instance, DeepCopy(fieldValue));
            }
            return instance;
        }
        else
            return null;
    }

但是在Activator.CreateInstance时出现System.MissingMethodException,因为System.Text.DecoderNLS和System.IO.Ports.SerialStream没有定义无参构造函数。

所以我就这样深拷贝

using (var ms = new MemoryStream())
{
    var formatter = new BinaryFormatter();
    formatter.Serialize(ms, this);
    ms.Position = 0;

    return formatter.Deserialize(ms);
}

又出现错误...

The type 'System.IO.Ports.SerialPort' is not marked as serializable.'

其次,我制作了简单的串口class,仅供串口打开。

//SimpleSerial
...
public SerialPort OpenSerial(string port, int baud)
{
    ...
    serial.Open();
    return serial;
}

其他class也这样变化。

// main.cs
SimpleSerial simple = new SimpleSerial()    
SerialPort serial = simple.OpenSerial("COM12", 9600);
list_Meters[i].SetSerialPort(serial);


// meter.cs
public void SetSerialPort(SerialPort serial)
{
    serialclass.Set(serial);
}

// SerialClass.cs

public void Set(SerialPort serial)
{
    this.serial = serial;
    serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
}

我想让每个仪表的序列号 class 的接收事件正常工作。但是,只有第一个生成的仪表的接收事件被触发。

我猜这是因为每个仪表共享一个串口实例。

但是 SerialPort 无法进行深度复制。

如何深度复制串口?

或者有没有其他方法可以在多个 class 中使用一个串口?

一次只能为一个特定的物理端口打开一个串行端口实例,因此尝试复制没有意义。

相反,您可以做的是拥有一个自定义实例 class,例如拥有串行端口实例的 PortManager,然后提供订阅机制,其中多个客户端 classes 可以向回调委托注册,订阅传入数据,可能基于端口管理器然后过滤传入数据的密钥并计算出哪些客户端应该接收这个特定的传入数据。

据推测,端口管理器也会有一个public发送方法,允许客户端通过端口发送数据。