C# Каждый класс пишет и получает по одному SerialPort или как DeepCopy SerialPort?

У меня три класса, основной, серийный, метровый.

главное создать новый экземпляр счетчика и добавить список для управления, когда пользователь нажимает кнопку.

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

И каждый счетчик имеет экземпляр последовательного класса и управляет им.

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

И серийный класс работает для последовательного открытия, закрытия, чтения, записи.

// 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;
}

Хорошо работает, если у счетчика есть собственный порт.

Но я хочу, чтобы счетчик делил один порт. Последовательный класс не отвечает, если его идентификатор счетчика не соответствует идентификатору счетчика пакета.

Как счетчик может разделить один порт?

во-первых, я попробовал открыть серийный номер в основном классе, и каждый класс счетчика выполняет глубокую копию последовательного класса.

    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;
    }

Но возникает System.MissingMethodException, когда Activator.CreateInstance, потому что 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.'

Во-вторых, я делаю простой последовательный класс только для последовательного открытия.

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

И другие подобные изменения класса.

// 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);
}

Я предполагал, что полученное событие серийного класса каждого измерителя будет работать. Однако срабатывает только полученное событие первого сгенерированного счетчика.

Я предполагаю, что это потому, что каждый счетчик использует один экземпляр последовательного порта.

Но SerialPort не работает с глубоким копированием.

Как я могу глубоко скопировать SerialPort?

Или есть другой способ использовать один последовательный порт в нескольких классах?


person NWOWN    schedule 10.09.2019    source источник
comment
Возможный дубликат Доступ к последовательному порту из нескольких классов   -  person Jazb    schedule 10.09.2019
comment
он может написать пакет, но как полученный каждым классом?   -  person NWOWN    schedule 10.09.2019
comment
Можете ли вы попробовать использовать шаблон публикации/подписки? например события   -  person Jazb    schedule 10.09.2019


Ответы (1)


Для конкретного физического порта одновременно может быть открыт только один экземпляр последовательного порта, поэтому нет смысла пытаться делать копии.

Вместо этого вы могли бы иметь один экземпляр пользовательского класса, например. PortManager, который владеет экземпляром последовательного порта, а затем предоставляет механизм подписки, в котором несколько клиентских классов могут регистрироваться с помощью делегата обратного вызова, подписываясь на входящие данные, возможно, на основе ключа, который диспетчер портов затем фильтрует входящие данные и вычисляет, какие клиенты должны получать этот конкретный фрагмент входящих данных.

Предположительно, диспетчер портов также будет иметь общедоступный метод Send, позволяющий клиентам отправлять данные через порт.

person 500 - Internal Server Error    schedule 10.09.2019