在C# .NET Core中如何反序列化PagedList泛型分页对象?
PagedList<T>的构造器匹配问题 咱们先拆解下报错的核心原因:Newtonsoft.Json在反序列化时,找不到能和JSON字段对应上的构造器参数。你的PagedList<T>里虽然有标记[JsonConstructor]的构造器,但构造器中的totalRecord参数名,和JSON里的TotalItems字段名不匹配,序列化器没法自动关联这两者,所以抛出了找不到合适构造器的异常。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:修改构造器参数名匹配JSON字段(最直接)
把构造器里的totalRecord参数改成totalItems,让参数名和JSON的键完全一致,序列化器就能自动匹配了。修改后的代码如下:
[JsonConstructor] public PagedList(IEnumerable<T> source, int totalItems, int pageNumber, int pageSize) { TotalItems = totalItems; PageNumber = pageNumber; PageSize = pageSize; List = source.ToList(); } // 如果需要保留IQueryable版本,同样修改参数名并标记JsonConstructor [JsonConstructor] public PagedList(IQueryable<T> source, int totalItems, int pageNumber, int pageSize) { TotalItems = totalItems; PageNumber = pageNumber; PageSize = pageSize; List = source.ToList(); }
注意:如果两个构造器都标记[JsonConstructor],序列化器会优先匹配参数类型和数量更贴合JSON数据的那个——你的JSON里List是数组,对应IEnumerable<T>,所以第一个构造器会被优先选中。
方案2:用JsonProperty标记构造器参数指定映射(无需修改参数名)
如果不想改动参数名称,可以给totalRecord参数加上[JsonProperty("TotalItems")],明确告诉序列化器这个参数对应JSON里的哪个字段:
[JsonConstructor] public PagedList(IEnumerable<T> source, [JsonProperty("TotalItems")] int totalRecord, int pageNumber, int pageSize) { TotalItems = totalRecord; PageNumber = pageNumber; PageSize = pageSize; List = source.ToList(); }
这样即使参数名和JSON键不一致,序列化器也能正确完成映射。
方案3:自定义JsonConverter(适合无法修改原类的场景)
如果你不能修改PagedList<T>的源代码,可以自定义一个转换器手动处理反序列化逻辑:
public class PagedListConverter<T> : JsonConverter<PagedList<T>> { public override PagedList<T> ReadJson(JsonReader reader, Type objectType, PagedList<T> existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var totalItems = jsonObject["TotalItems"].Value<int>(); var pageNumber = jsonObject["PageNumber"].Value<int>(); var pageSize = jsonObject["PageSize"].Value<int>(); var list = jsonObject["List"].ToObject<List<T>>(serializer); return new PagedList<T>(list, totalItems, pageNumber, pageSize); } public override void WriteJson(JsonWriter writer, PagedList<T> value, JsonSerializer serializer) { // 如果需要支持序列化,这里可以补充写入逻辑 var jsonObject = new JObject { ["TotalItems"] = value.TotalItems, ["PageNumber"] = value.PageNumber, ["PageSize"] = value.PageSize, ["List"] = JArray.FromObject(value.List, serializer) }; jsonObject.WriteTo(writer); } }
使用时在反序列化方法中指定这个转换器即可:
var pagedList = JsonConvert.DeserializeObject<PagedList<Dvhc>>(jsonString, new PagedListConverter<Dvhc>());
也可以把转换器加入全局序列化设置,让所有PagedList<T>的反序列化都自动使用它。
为什么不能用默认构造器?
你代码里注释了默认构造器,但即使打开它也没法正常工作——因为你的TotalItems、PageNumber等属性都是只读的(只有get;没有set;),Newtonsoft.Json无法给这些只读属性赋值,最终会得到一个所有属性都是默认值的无效对象,所以这条路走不通。
内容的提问来源于stack exchange,提问作者quanchinhong

