继承DynamicObject的类调用JsonConvert.SerializeObject时动态属性未序列化
解决DynamicObject子类动态属性无法被JsonConvert序列化的问题
嘿,这个问题我之前帮不少开发者踩过坑——当你继承DynamicObject时,Json.NET默认确实不会自动序列化那些动态添加的属性,因为它没办法直接感知到这些属性的存在。别担心,咱们一步步来搞定它!
问题根源
DynamicObject只是提供了动态操作的框架(比如TrySetMember、TryGetMember方法),但它本身不会主动维护动态属性的集合,也不会主动把这些属性暴露给序列化工具。Json.NET默认只会反射类的静态定义的属性/字段,不会主动调用DynamicObject的方法去获取动态成员列表,所以自然就序列化不了那些动态添加的属性。
最直接的解决方案:重写GetDynamicMemberNames并维护属性存储
要让Json.NET识别动态属性,你需要做两件事:
- 在自定义类内部维护一个字典,用来存储所有动态添加的属性键值对
- 重写
GetDynamicMemberNames方法,返回所有动态属性的名称列表
修改后的自定义类示例
public class MyDynamicClass : DynamicObject { // 用来存储所有动态属性的键值对 private readonly Dictionary<string, object> _dynamicProperties = new Dictionary<string, object>(); // 重写TrySetMember,把动态属性存入字典 public override bool TrySetMember(SetMemberBinder binder, object value) { _dynamicProperties[binder.Name] = value; return true; // 返回true表示设置成功 } // 重写TryGetMember,从字典中获取动态属性值 public override bool TryGetMember(GetMemberBinder binder, out object result) { return _dynamicProperties.TryGetValue(binder.Name, out result); } // 关键:告诉Json.NET有哪些动态属性需要序列化 public override IEnumerable<string> GetDynamicMemberNames() { return _dynamicProperties.Keys; } }
测试序列化
// 创建动态对象并添加属性 dynamic myDynamicObj = new MyDynamicClass(); myDynamicObj.Username = "Usman"; myDynamicObj.Email = "usman@example.com"; myDynamicObj.Age = 28; // 执行序列化 string jsonResult = JsonConvert.SerializeObject(myDynamicObj); // 输出结果:{"Username":"Usman","Email":"usman@example.com","Age":28} Console.WriteLine(jsonResult);
进阶方案:自定义ContractResolver(无需修改原类)
如果因为某些原因你不能修改原有的DynamicObject子类,可以通过自定义ContractResolver来强制Json.NET识别动态属性:
自定义ContractResolver代码
public class DynamicObjectContractResolver : DefaultContractResolver { protected override JsonContract CreateContract(Type objectType) { // 针对所有继承自DynamicObject的类型创建动态契约 if (typeof(DynamicObject).IsAssignableFrom(objectType)) { var dynamicContract = new JsonDynamicContract(objectType); // 覆盖获取动态成员名称的逻辑 dynamicContract.GetDynamicMemberNames = obj => { if (obj is DynamicObject dynamicObj) { return dynamicObj.GetDynamicMemberNames(); } return Enumerable.Empty<string>(); }; return dynamicContract; } return base.CreateContract(objectType); } }
使用方式
var serializerSettings = new JsonSerializerSettings { ContractResolver = new DynamicObjectContractResolver() }; string jsonResult = JsonConvert.SerializeObject(myDynamicObj, serializerSettings);
注意事项
- 如果你没有在自定义类中维护动态属性的存储(比如用字典),即使重写了
GetDynamicMemberNames也没用,因为Json.NET获取到属性名称后,还是需要通过TryGetMember拿到对应的值。 - 如果动态属性包含复杂类型(比如自定义对象、枚举),Json.NET会自动处理,不需要额外配置,除非你有特殊的序列化需求。
内容的提问来源于stack exchange,提问作者Usman Khan
相关产品推荐
相关产品推荐

