首页 > 解决方案 > 将嵌套在动态对象中的 C# 列表中的第一项和最后一项序列化为 JSON

问题描述

我有一个类需要将任何类型的对象序列化为 JSON。如果对象具有一个或多个类型为列表的属性,我想序列化整个对象,但只序列化列表中的第一个和最后一个项目。

例如,我有以下代码

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections;
using Newtonsoft.Json.Serialization;
using System.Linq;
using Newtonsoft.Json.Linq;

public class Program
{
    public class Product{
        public Product(string name, int price){
            this.Name = name;
            this.Price = price;
        }
        public string Name {get;set;}
        public int Price {get;set;}
    }

    public class ProductResult{
        public ProductResult(List<Product> products, int code){
            this.Products = products;
            this.Code = code;
        }
        public int Code {get;set;}
        public List<Product> Products {get;set;}    
    }

    public static string DoTheThing(object dynamicObject){
        return JsonConvert.SerializeObject(dynamicObject);
    }

    public static void Main()
    {
        var list = new List<Product>(){new Product("product1",100),new Product("product2",100),new Product("product3",100),new Product("product4",100)};
        var result = new ProductResult(list,0);

        string jsonObj = DoTheThing(result);
        Console.WriteLine(jsonObj);
        // Output {"Code":0,"Products":[{"Name":"product1","Price":100},{"Name":"product2","Price":100},{"Name":"product3","Price":100},{"Name":"product4","Price":100}]}
    }
}

我希望它输出以下内容,并且我需要它能够处理各种对象类型。

{"Code":0,"Products":[{"Name":"product","Price":100},{"Name":"product","Price":100}]}

我查看了使用Custom JsonConverterCustom ContractResolver但不确定如何实现这些。

标签: c#.netjsonserializationjson.net

解决方案


您可以将 aCustom ContractResolver与 a 一起使用ValueConverter。例如,

public class ListContractResolver : DefaultContractResolver
{
    public new static readonly ListContractResolver  Instance = new ListContractResolver ();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (property.PropertyType.IsGenericType &&   property.PropertyType.GetInterfaces().Contains(typeof(IList)))
        {
           property.ValueProvider = new FilterListValueProvider(member as PropertyInfo);
        }
        return property;
    }
}

public class FilterListValueProvider : IValueProvider
{
    PropertyInfo _propertyInfo;
    public FilterListValueProvider(PropertyInfo propertyInfo)
    {
        _propertyInfo = propertyInfo;
    }

    public object GetValue(object target)
    {
        return GetList(target);
    }

    public IEnumerable GetList(object target)
    {
        var list = _propertyInfo.GetValue(target) as IList;
        yield return list[0];
        yield return list[list.Count - 1];
    }

    public void SetValue(object target, object value)
    {
        _propertyInfo.SetValue(target, value);
    }
}

更新您的DoTheThing方法以使用ListContractResolver我们定义为

public static string DoTheThing(object dynamicObject)
{
        return JsonConvert.SerializeObject(dynamicObject,
                                   Newtonsoft.Json.Formatting.Indented, 
                                   new JsonSerializerSettings 
                                   { ContractResolver = new ListContractResolver() });
}

样本输出

{
  "Code": 0,
  "Products": [
    {
      "Name": "product1",
      "Price": 100
    },
    {
      "Name": "product4",
      "Price": 100
    }
  ]
}

推荐阅读