У меня три класса, основной, серийный, метровый.
главное создать новый экземпляр счетчика и добавить список для управления, когда пользователь нажимает кнопку.
// 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?
Или есть другой способ использовать один последовательный порт в нескольких классах?