0

0

C#的Serializable特性如何实现对象序列化?

月夜之吻

月夜之吻

发布时间:2025-08-04 11:05:01

|

294人浏览过

|

来源于php中文网

原创

c#中的serializable特性用于标记可序列化类,真正执行序列化的是formatter类,如binaryformatter。1. 使用[serializable]特性标记类以启用序列化;2. 通过binaryformatter将对象序列化到文件流或内存流中;3. 反序列化时使用相同formatter从流中恢复对象;4. 用[nonserialized]标记不希望序列化的字段;5. binaryformatter虽使用简单但存在安全风险且性能较差,现更推荐jsonserializer等现代序列化器;6. 为解决版本控制问题,可实现iserializable接口,通过getobjectdata和带serializationinfo的构造函数手动管理序列化过程,并处理新增字段的默认值;7. 可利用序列化实现深拷贝,通过memorystream配合序列化与反序列化创建独立副本,但该方法性能较低且有安全风险,应谨慎使用。

C#的Serializable特性如何实现对象序列化?

C#的Serializable特性通过标记类,让CLR知道该类的对象可以被序列化,进而转换为字节流或其他格式,以便存储或传输。本质上,它告诉.NET运行时,这个类的实例可以被“冻结”成数据,并在需要的时候“解冻”回来。

解决方案:

Serializable特性只是一个标记,真正执行序列化和反序列化的是Formatter类,例如BinaryFormatter或XmlSerializer。

  1. 标记可序列化类: 在你的类定义上方添加

    [Serializable]
    特性。

    [Serializable]
    public class MyClass
    {
        public int Value1 { get; set; }
        public string Value2 { get; set; }
    }
  2. 使用Formatter进行序列化: 使用

    BinaryFormatter
    (或其他Formatter)将对象序列化到流中。

    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    public static void SerializeObject(MyClass obj, string filename)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        using (FileStream stream = new FileStream(filename, FileMode.Create))
        {
            formatter.Serialize(stream, obj);
        }
    }
  3. 使用Formatter进行反序列化: 使用相同的Formatter从流中反序列化对象。

    public static MyClass DeserializeObject(string filename)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        using (FileStream stream = new FileStream(filename, FileMode.Open))
        {
            return (MyClass)formatter.Deserialize(stream);
        }
    }
  4. 忽略序列化属性: 有时候,你可能希望某些属性不被序列化。使用

    [NonSerialized]
    特性标记这些属性。

    [Serializable]
    public class MyClass
    {
        public int Value1 { get; set; }
        [NonSerialized]
        public string Value2; // Value2不会被序列化
    }

为什么选择BinaryFormatter而不是其他的序列化方式?

BinaryFormatter是.NET早期提供的序列化工具,使用简单,但存在一些问题。比如,它会序列化对象的私有成员,这可能违反封装性。另外,BinaryFormatter的安全性也受到质疑,因为它可以执行任意代码,因此在反序列化不受信任的数据时存在风险。现在,更推荐使用

JsonSerializer
DataContractSerializer
,它们更安全,性能也更好。

百度MCP广场
百度MCP广场

探索海量可用的MCP Servers

下载

序列化版本控制问题:如何处理类的修改?

当类的结构发生变化时(例如添加、删除或修改属性),反序列化旧版本的数据可能会失败。为了解决这个问题,可以使用

ISerializable
接口和
SerializationInfo
类来手动控制序列化和反序列化过程。

  1. 实现ISerializable接口: 让你的类实现

    ISerializable
    接口。

    [Serializable]
    public class MyClass : ISerializable
    {
        public int Value1 { get; set; }
        public string Value2 { get; set; }
    
        public MyClass() { } // 必须要有默认构造函数
    
        protected MyClass(SerializationInfo info, StreamingContext context)
        {
            Value1 = info.GetInt32("Value1");
            Value2 = info.GetString("Value2");
    
            // 处理旧版本数据,例如:
            try {
                Value3 = info.GetString("Value3");
            } catch (SerializationException) {
                Value3 = "DefaultValue"; // 提供默认值
            }
        }
    
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Value1", Value1);
            info.AddValue("Value2", Value2);
            info.AddValue("Value3", Value3);
        }
    
        public string Value3 { get; set; }
    }
  2. GetObjectData方法:

    GetObjectData
    方法中,将需要序列化的数据添加到
    SerializationInfo
    对象中。

  3. 构造函数重载: 提供一个受保护的构造函数,该构造函数接受

    SerializationInfo
    StreamingContext
    作为参数。在这个构造函数中,从
    SerializationInfo
    对象中读取数据,并初始化对象的属性。

  4. 处理版本差异: 在反序列化构造函数中,使用try-catch块来处理旧版本数据中不存在的属性。为这些属性提供默认值,以确保反序列化过程不会失败。

使用序列化进行深拷贝:可行吗?

是的,序列化可以用来实现对象的深拷贝。通过将对象序列化到内存流中,然后再反序列化回来,可以创建一个与原始对象具有相同状态的全新对象。这种方法可以避免浅拷贝带来的引用问题。

public static T DeepClone(T obj)
{
    using (MemoryStream stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, obj);
        stream.Position = 0;
        return (T)formatter.Deserialize(stream);
    }
}

//用法:
MyClass originalObject = new MyClass { Value1 = 1, Value2 = "Hello" };
MyClass clonedObject = DeepClone(originalObject);

// 验证是否是深拷贝
clonedObject.Value1 = 2;
Console.WriteLine(originalObject.Value1); // 输出 1
Console.WriteLine(clonedObject.Value1); // 输出 2

不过,需要注意的是,使用BinaryFormatter进行深拷贝可能会比较慢,特别是对于大型对象。对于性能要求较高的场景,可以考虑使用其他深拷贝方法,例如手动复制对象属性或使用第三方库。另外,使用BinaryFormatter进行深拷贝也存在安全风险,因此需要谨慎使用。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1024

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

66

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

450

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.19

xml格式相关教程
xml格式相关教程

本专题整合了xml格式相关教程汇总,阅读专题下面的文章了解更多详细内容。

0

2026.01.19

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

13

2026.01.19

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

87

2026.01.18

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

111

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

155

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.1万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 12.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号