using System; using System.Reflection; using System.Text; namespace DanroJump.Hardware.Com { public sealed class ReflectionSerialComTransportFactory : IComTransportFactory { public IComTransport Create(SerialSettings settings) { return ReflectionSerialComTransport.Create(settings); } } internal sealed class ReflectionSerialComTransport : IComTransport { private static readonly Type SerialPortType = Type.GetType("System.IO.Ports.SerialPort, System"); private static readonly Type ParityType = Type.GetType("System.IO.Ports.Parity, System"); private static readonly Type StopBitsType = Type.GetType("System.IO.Ports.StopBits, System"); private readonly object instance; private ReflectionSerialComTransport(object instance) { this.instance = instance; } public bool IsOpen => (bool)GetProperty("IsOpen"); public static ReflectionSerialComTransport Create(SerialSettings settings) { if (SerialPortType == null) { throw new InvalidOperationException("System.IO.Ports.SerialPort is not available."); } object serialPort = Activator.CreateInstance(SerialPortType, settings.PortName, settings.BaudRate); var transport = new ReflectionSerialComTransport(serialPort); transport.SetProperty("DataBits", settings.DataBits); transport.SetProperty("Parity", ParseEnum(ParityType, settings.Parity.ToString())); transport.SetProperty("StopBits", ParseEnum(StopBitsType, settings.StopBits.ToString())); transport.SetProperty("ReadTimeout", settings.ReadTimeoutMs); transport.SetProperty("WriteTimeout", settings.WriteTimeoutMs); transport.SetProperty("NewLine", "\n"); transport.SetProperty("Encoding", Encoding.UTF8); transport.SetProperty("DtrEnable", true); transport.SetProperty("RtsEnable", true); return transport; } public void Open() { Invoke("Open"); } public void Close() { Invoke("Close"); } public void DiscardInBuffer() { Invoke("DiscardInBuffer"); } public void DiscardOutBuffer() { Invoke("DiscardOutBuffer"); } public string ReadLine() { return (string)Invoke("ReadLine"); } public void WriteLine(string value) { Invoke("WriteLine", value); } public void Dispose() { if (instance is IDisposable disposable) { disposable.Dispose(); } } private object GetProperty(string propertyName) { return SerialPortType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance) ?.GetValue(instance); } private void SetProperty(string propertyName, object value) { SerialPortType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance) ?.SetValue(instance, value); } private object Invoke(string methodName, params object[] args) { try { return SerialPortType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance) ?.Invoke(instance, args); } catch (TargetInvocationException exception) when (exception.InnerException != null) { throw exception.InnerException; } } private static object ParseEnum(Type enumType, string value) { if (enumType == null) { throw new InvalidOperationException("System.IO.Ports enum metadata is not available."); } return Enum.Parse(enumType, value); } } }