基于反射实现对象反序列化:遍历字段从SerializationInfo取值
用反射实现对象的反序列化逻辑
嘿,我懂你现在的需求——之前手动写反序列化构造函数,每次加新字段都要改代码,太麻烦了对吧?用反射来自动遍历字段赋值确实能省不少事,我来给你一步步讲怎么实现:
核心思路
通过反射获取类的所有字段,逐个从SerializationInfo中取出对应值并赋值给当前实例,同时跳过不需要序列化的字段。
具体实现步骤
- 首先确保你的类标记了
[Serializable]特性,并且实现了ISerializable接口(如果是自定义序列化的话):[Serializable] public class SKA_MAP : ISerializable { // 你的字段定义 } - 在反序列化构造函数中,用反射获取字段并处理:
- 获取类的所有实例字段(包括私有字段,可根据需求调整绑定标志):
var fields = typeof(SKA_MAP).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - 遍历字段,跳过
[NonSerialized]标记的字段,从SerializationInfo取值并赋值:foreach (var field in fields) { // 跳过不需要序列化的字段 if (field.GetCustomAttribute<NonSerializedAttribute>() != null) continue; // 检查SerializationInfo中是否存在该字段,避免报错 if (info.MemberNames.Contains(field.Name)) { try { var value = info.GetValue(field.Name, field.FieldType); field.SetValue(this, value); } catch (Exception ex) { // 可根据需求添加异常处理,比如日志 Console.WriteLine($"反序列化字段 {field.Name} 失败: {ex.Message}"); } } }
- 获取类的所有实例字段(包括私有字段,可根据需求调整绑定标志):
完整示例代码
[Serializable] public class SKA_MAP : ISerializable { // 示例字段 public int MapId; private string MapName; [NonSerialized] public string TemporaryData; // 这个字段不会被序列化/反序列化 // 反序列化构造函数 public SKA_MAP(SerializationInfo info, StreamingContext ctxt) { // 获取所有实例字段(公共+私有) var fields = typeof(SKA_MAP).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var field in fields) { // 跳过NonSerialized字段 if (field.GetCustomAttribute<NonSerializedAttribute>() != null) continue; if (info.MemberNames.Contains(field.Name)) { try { var fieldValue = info.GetValue(field.Name, field.FieldType); field.SetValue(this, fieldValue); } catch (Exception ex) { Console.WriteLine($"处理字段 {field.Name} 出错: {ex.Message}"); } } } } // 序列化方法,同样用反射保持逻辑一致 public void GetObjectData(SerializationInfo info, StreamingContext context) { var fields = typeof(SKA_MAP).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var field in fields) { if (field.GetCustomAttribute<NonSerializedAttribute>() != null) continue; info.AddValue(field.Name, field.GetValue(this)); } } }
注意事项
- 绑定标志调整:如果只需要处理公共字段,去掉
BindingFlags.NonPublic即可;如果要包含静态字段,添加BindingFlags.Static(不过反序列化一般用实例字段)。 - 字段名一致性:序列化和反序列化时的字段名必须完全匹配,用反射实现
GetObjectData能保证这一点,避免手动写错。 - 继承处理:如果你的类继承自其他可序列化类,记得在构造函数开头调用
base(info, ctxt);,否则基类的字段无法被反序列化。
内容的提问来源于stack exchange,提问作者tobeypeters
相关产品推荐
相关产品推荐

