序列化Realm对象为JSON时抛出Newtonsoft.Json.JsonSerializationException
异常触发根因
- Realm生成的托管对象是动态代理类型,所有属性访问都绑定对象创建时的Realm数据库上下文与对应线程,跨线程读取属性值会直接抛出底层异常,被Newtonsoft.Json捕获后就会提示“读取属性值时出错”
- Newtonsoft.Json默认没有内置MongoDB
ObjectId类型的序列化逻辑,直接序列化该类型会因为无法解析内部结构抛出序列化错误 - 原代码将序列化逻辑放入
Task.Run的后台线程执行,直接触发了Realm对象的线程亲和性限制,是本次报错的直接诱因
修复方案
- 杜绝直接序列化Realm托管代理对象:在获取Realm对象的当前线程,手动将各属性值映射到无Realm依赖的纯内存DTO类中,从根源上规避代理对象的上下文绑定问题
- 对主键类型做适配转换:将可空的
ObjectId类型转为字符串存入DTO,适配Newtonsoft.Json的默认序列化规则 - 取消不必要的后台线程序列化操作:纯POCO对象的序列化计算量极低,不需要放入后台线程执行,避免多余的线程切换触发访问异常
代码实现参考
- 定义跨页面传输用的纯DTO类
public class ProductDetailDto { public string Id { get; set; } public string Brand { get; set; } public string ImageUrl { get; set; } public string Name { get; set; } }
- 调整原事件方法的序列化逻辑
async void OnItemSelected(product item) { if (item == null) return; var model = await ProductService.GetProduct(item.Id); // 在当前线程完成Realm对象的属性值提取 var detailDto = new ProductDetailDto { Id = model.Id?.ToString(), Brand = model.Brand, ImageUrl = model.ImageUrl, Name = model.Name }; // 对无依赖的纯DTO执行序列化 string jsonStrObj = JsonConvert.SerializeObject(detailDto); // 执行页面导航跳转 await Shell.Current.GoToAsync($"{nameof(ItemDetailPage)}?ProductModel={jsonStrObj}"); }
提示:后续涉及Realm对象的跨线程、跨模块、跨页面传递场景,都需要提前做DTO映射,不要直接传递Realm原生托管对象,避免出现同类的访问异常。
内容的提问来源于stack exchange,提问作者PHULUSO GOVERN RAMULIFHO
相关产品推荐
相关产品推荐

