You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:11:16