如何为SerialPort类实现依赖注入 无法通过ICommand调用其方法
依赖注入解耦SerialPort实现方案
.NET 官方提供的 SerialPort 类没有适配串口操作的专用公开接口,其仅实现的 ICommand 接口不包含任何串口相关的业务成员,无法满足调用需求,因此你需要自定义抽象接口来完成解耦,具体实现步骤如下:
步骤1:自定义串口操作抽象接口
将你业务中用到的所有 SerialPort 成员定义到接口中,示例代码如下:
public interface ISerialPort : IDisposable { // 你用到的DataReceived事件 event SerialDataReceivedEventHandler DataReceived; // 你用到的Open、Close方法 void Open(); void Close(); // 如需获取串口号可补充该属性 string PortName { get; } // 后续如果用到Write、Read等其他SerialPort方法,可在此处补充定义 }
步骤2:实现SerialPort适配类
基于原生SerialPort写适配类,实现你定义的ISerialPort接口:
public class SerialPortAdapter : ISerialPort { private readonly SerialPort _serialPort; public SerialPortAdapter(string comPort, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One, Handshake handshake = Handshake.None) { _serialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBits) { Handshake = handshake }; } public event SerialDataReceivedEventHandler DataReceived { add => _serialPort.DataReceived += value; remove => _serialPort.DataReceived -= value; } public string PortName => _serialPort.PortName; public void Open() => _serialPort.Open(); public void Close() => _serialPort.Close(); public void Dispose() => _serialPort.Dispose(); }
步骤3:改造原有业务类使用依赖注入
将CommandService的依赖改为抽象接口,不再在构造函数中自行初始化SerialPort实例:
public class CommandService : IDisposable { private readonly ISerialPort _serialPort; // 直接注入ISerialPort实例,初始化逻辑交给DI容器处理 public CommandService(ISerialPort serialPort) { _serialPort = serialPort; try { _serialPort.Open(); } catch (System.IO.FileNotFoundException) { throw new Exception($"Serialport {_serialPort.PortName} can't be found"); } _serialPort.DataReceived += DataReceived; } // 保留你原有的DataReceived业务处理逻辑 private void DataReceived(object sender, SerialDataReceivedEventArgs e) { // 原有业务代码不变 } public void Dispose() { _serialPort.Close(); _serialPort.Dispose(); } }
步骤4:DI容器注册示例(以.NET默认DI容器为例)
在服务注册处配置串口参数和依赖映射:
// 注册串口实例,按需配置串口参数 services.AddScoped<ISerialPort>(sp => new SerialPortAdapter("COM3", 9600, Parity.None, 8, StopBits.One, Handshake.None)); // 注册业务服务 services.AddScoped<CommandService>();
方案优势
- 完全解除业务层和原生
SerialPort的耦合,单元测试时可直接MockISerialPort接口,无需依赖真实串口硬件 - 后续需要替换串口实现(比如第三方串口库、虚拟串口模拟)时,只需新增
ISerialPort的实现类即可,无需修改业务代码 - 串口参数、实例生命周期都交由DI容器统一管理,避免硬编码参数
内容的提问来源于stack exchange,提问作者CSharpFan
相关产品推荐
相关产品推荐

