VB.NET序列化报错:System.ComponentModel.Component.Site接口无法序列化
问题解决:XML序列化时System.InvalidOperationException错误
错误原因
你遇到的错误是因为直接序列化了SerialPort和sqlConnector这类包含Component派生类的对象。Component类包含Site属性(类型为ISite接口),而XML序列化器不支持序列化接口类型。此外,SerialPort、SqlConnection这类类包含运行时连接状态、句柄等资源,本身就不适合直接序列化。
解决方案:分离配置数据与业务逻辑类
最可靠的方式是创建专门的配置数据传输对象(DTO),只存储需要持久化的配置信息,而非直接序列化业务逻辑类。具体步骤如下:
1. 创建配置DTO类
定义只包含配置属性的类,用于序列化/反序列化:
' SQL连接配置DTO Public Class SqlConfigDTO Public Property ServerName As String Public Property UserName As String Public Property Password As String Public Property DatabaseName As String Public Property Table As String End Class ' 串口配置DTO Public Class SerialPortConfigDTO Public Property PortName As String Public Property BaudRate As Integer Public Property Parity As Integer Public Property DataBits As Integer Public Property StopBits As Integer End Class ' 秤具配置DTO Public Class ScaleConfigDTO Public Property Name As String Public Property Id As Integer Public Property SqlConfig As SqlConfigDTO Public Property SerialConfig As SerialPortConfigDTO End Class
2. 修改Settings类适配DTO
更新Settings类,使用DTO存储配置,而非业务对象:
Public Class Settings Private pFileName As String Private pScaleConfigs As New List(Of ScaleConfigDTO) Private pSqlConfigs As New List(Of SqlConfigDTO) Public Sub New() End Sub Public Sub SaveSettings() If pFileName Is Nothing Then pFileName = Application.StartupPath & "\settings.cfg" End If ' 序列化配置列表 Dim serializer As New XmlSerializer(GetType(ConfigContainer)) Using writer As New StreamWriter(pFileName) serializer.Serialize(writer, New ConfigContainer With { .ScaleConfigs = pScaleConfigs, .SqlConfigs = pSqlConfigs }) End Using End Sub Public Sub LoadSettings() If Not File.Exists(pFileName) Then Return Dim serializer As New XmlSerializer(GetType(ConfigContainer)) Using reader As New StreamReader(pFileName) Dim container = DirectCast(serializer.Deserialize(reader), ConfigContainer) pScaleConfigs = container.ScaleConfigs pSqlConfigs = container.SqlConfigs End Using End Sub ' 添加配置的方法 Public Sub AddScaleConfig(config As ScaleConfigDTO) pScaleConfigs.Add(config) End Sub Public Sub AddSqlConfig(config As SqlConfigDTO) pSqlConfigs.Add(config) End Sub ' 辅助类:用于序列化根容器 <XmlRoot("Settings")> Private Class ConfigContainer Public Property ScaleConfigs As List(Of ScaleConfigDTO) Public Property SqlConfigs As List(Of SqlConfigDTO) End Class End Class
3. 业务类从DTO加载配置
在sqlConnector和Scale类中添加从DTO初始化的方法:
Public Class sqlConnector ' ... 原有代码 ... ' 从DTO加载配置 Public Sub LoadFromConfig(config As SqlConfigDTO) Me.serverName = config.ServerName Me.userName = config.UserName Me.password = config.Password Me.dataBaseName = config.DatabaseName Me.table = config.Table End Sub End Class Public Class Scale ' ... 原有代码 ... ' 从DTO加载配置 Public Sub LoadFromConfig(config As ScaleConfigDTO, sqlConn As sqlConnector, serialPort As SerialPort) Me.name = config.Name Me.id = config.Id Me.sqlConnection = sqlConn ' 配置串口 serialPort.PortName = config.SerialConfig.PortName serialPort.BaudRate = config.SerialConfig.BaudRate serialPort.Parity = DirectCast(config.SerialConfig.Parity, Parity) serialPort.DataBits = config.SerialConfig.DataBits serialPort.StopBits = DirectCast(config.SerialConfig.StopBits, StopBits) Me.serialConnection = serialPort End Sub End Class
4. 修改主逻辑,生成DTO并序列化
Module modMain Public scales As New List(Of Scale) Public settings As New Settings Public Sub Main() ' 创建配置DTO Dim sqlConfig As New SqlConfigDTO With { .ServerName = "your_server", .UserName = "your_user", .Password = "your_pwd", .DatabaseName = "your_db", .Table = "your_table" } Dim serialConfig As New SerialPortConfigDTO With { .PortName = "COM1", .BaudRate = 9600, .Parity = CInt(Parity.None), .DataBits = 8, .StopBits = CInt(StopBits.One) } Dim scaleConfig As New ScaleConfigDTO With { .Name = "scale01", .Id = 178, .SqlConfig = sqlConfig, .SerialConfig = serialConfig } ' 添加到配置并保存 settings.AddScaleConfig(scaleConfig) settings.AddSqlConfig(sqlConfig) settings.SaveSettings() ' 从配置加载业务对象示例 Dim sqlConn As New sqlConnector() sqlConn.LoadFromConfig(sqlConfig) Dim serialPort As New SerialPort() Dim scale As New Scale() scale.LoadFromConfig(scaleConfig, sqlConn, serialPort) scales.Add(scale) End Sub End Module
替代方案:忽略不可序列化属性
如果不想创建DTO,可以在业务类的不可序列化属性上添加<XmlIgnore>特性,但注意运行时资源(如打开的连接)仍无法序列化,仅适合临时方案:
Public Class Scale ' ... 原有代码 ... <XmlIgnore> Public Property serialConnection As SerialPort ' ... 原有get/set ... End Property <XmlIgnore> Public Property sqlConnection As sqlConnector ' ... 原有get/set ... End Property End Class Public Class sqlConnector <XmlIgnore> Private pSqlConnection As New SqlConnection <XmlIgnore> Private pSqlCmd As SqlCommand <XmlIgnore> Private pSqlReader As SqlDataReader ' ... 原有代码 ... End Class
但这种方式会丢失串口和SQL连接的配置信息,仍推荐使用DTO方案。
内容的提问来源于stack exchange,提问作者bradacsa
相关产品推荐
相关产品推荐

