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

C#的Serializable特性通过标记类,让CLR知道该类的对象可以被序列化,进而转换为字节流或其他格式,以便存储或传输。本质上,它告诉.NET运行时,这个类的实例可以被“冻结”成数据,并在需要的时候“解冻”回来。
解决方案:
Serializable特性只是一个标记,真正执行序列化和反序列化的是Formatter类,例如BinaryFormatter或XmlSerializer。
标记可序列化类: 在你的类定义上方添加
[Serializable]特性。[Serializable] public class MyClass { public int Value1 { get; set; } public string Value2 { get; set; } }使用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); } }使用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); } }忽略序列化属性: 有时候,你可能希望某些属性不被序列化。使用
[NonSerialized]特性标记这些属性。[Serializable] public class MyClass { public int Value1 { get; set; } [NonSerialized] public string Value2; // Value2不会被序列化 }
为什么选择BinaryFormatter而不是其他的序列化方式?
BinaryFormatter是.NET早期提供的序列化工具,使用简单,但存在一些问题。比如,它会序列化对象的私有成员,这可能违反封装性。另外,BinaryFormatter的安全性也受到质疑,因为它可以执行任意代码,因此在反序列化不受信任的数据时存在风险。现在,更推荐使用JsonSerializer或DataContractSerializer,它们更安全,性能也更好。
序列化版本控制问题:如何处理类的修改?
当类的结构发生变化时(例如添加、删除或修改属性),反序列化旧版本的数据可能会失败。为了解决这个问题,可以使用ISerializable接口和SerializationInfo类来手动控制序列化和反序列化过程。
实现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; } }GetObjectData方法: 在
GetObjectData方法中,将需要序列化的数据添加到SerializationInfo对象中。构造函数重载: 提供一个受保护的构造函数,该构造函数接受
SerializationInfo和StreamingContext作为参数。在这个构造函数中,从SerializationInfo对象中读取数据,并初始化对象的属性。处理版本差异: 在反序列化构造函数中,使用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进行深拷贝也存在安全风险,因此需要谨慎使用。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















