JSON 在 C# 中使用 newtonsoft 进行序列化

JSON serialization using newtonsoft in C#

我有以下模型结构。

 public class ReferenceData
    {
        public string Version { get; set; }

        public List<DataItem> Data { get; set; }
    }


    public class DataItem
    {
        public Dictionary<string, string> Item { get; set; }
    }

在字典中,我添加了键值对并使用 KeyValuePairConverter 设置进行序列化。

var settings = new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    NullValueHandling = NullValueHandling.Ignore,
                    Converters = new List<JsonConverter>() { new KeyValuePairConverter() }
                };

var object =  Newtonsoft.Json.JsonConvert.SerializeObject(
                    referenceData,
                    Formatting.None,
                    settings
                    );

输出是,

 {  
       "data":[  
          {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          },
           {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          },
          {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          }
       ]
    }

如果我们不希望item显示在序列化字符串中,需要在JsonSerializerSettings中进行什么设置或者有没有其他方法可以做到这一点

请注意,我无法根据需要更改模型结构。

输出应该是:

{  
   "data":[  
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      },
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      },
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      }
   ]
}

如果你这样改变,结果就会如你所愿;

public class ReferenceData
{
    public string Version { get; set; }

    public List<Dictionary<string, string>> Data { get; set; }
}

可能的其他解决方案是;

ReferenceData r = new ReferenceData();

r.Data = new List<DataItem>();

r.Data.Add(new DataItem { Item = new Dictionary<string, string>() { { "1", "2" }, { "3", "4" } } });



var anon = new
{
    data = r.Data.ToList().Select(x =>
        {
            dynamic data = new ExpandoObject();

            IDictionary<string, object> dictionary = (IDictionary<string, object>)data;

            foreach (var key in x.Item.Keys)
                dictionary.Add(key, x.Item[key]);

            return dictionary;
       }
    )
};

var result = JsonConvert.SerializeObject(anon);

结果:

{
  "data": [
    {
      "1": "2",
      "3": "4"
    }
  ]
}

如果您不能更改 C#,可以使用视图模型并使用适当的结构。它可能比更改 JSON 设置更简单,更容易 return 并且更明确:

public class ReferenceData
{
    public string Version { get; set; }
    public List<Dictionary<string, string>> Data { get; set; }
}

应该根据需要进行序列化。

如果您使用 Json.NET 5.0 第 5 版或更高版本,则不需要嵌套泛型集合。 您可以使用 JsonExtensionDataAttribute 以便 Item 字典的键和值将被序列化为父对象的一部分。

public class ReferenceData
{
    public string version { get; set; }
    public List<DataItem> data { get; set; }
}

public class DataItem
{   
    [JsonExtensionData]
    public IDictionary<string, object> item { get; set; }
}

// ...

var referenceData = new ReferenceData {
    version = "1.0",
    data = new List<DataItem> {
        new DataItem {
            item = new Dictionary<string, object> {
                {"1", "2"},
                {"3", "4"}
            }
        },
        new DataItem {
            item = new Dictionary<string, object> {
                {"5", "8"},
                {"6", "7"}
            }
        }
    }
};

Console.WriteLine(JsonConvert.SerializeObject(referenceData));

请注意,您需要 Dictionary<string, object> 而不是 Dictionary<string, string>

这是我得到的结果:

{
  "version": "1.0",
  "data": [
    {
      "1": "2",
      "3": "4"
    },
    {
      "5": "8",
      "6": "7"
    }
  ]
}

显然,您可以删除 Version 属性 以获得预期的结果。

在此处阅读更多内容: http://james.newtonking.com/archive/2013/05/08/json-net-5-0-release-5-defaultsettings-and-extension-data

您可以按如下方式实现自定义行为:

class Program {
    static void Main(string[] args) {
        var referenceData = new ReferenceData() {
            Data = new List<DataItem>() {
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                },
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                },
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                }
            }
        };

        var settings = new JsonSerializerSettings {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore,
            Converters = new List<JsonConverter>() { new KeyValuePairConverter(), new CustomJsonSerializableConverter() }
        };

        File.WriteAllText("hello.json", Newtonsoft.Json.JsonConvert.SerializeObject(
            referenceData,
            Formatting.Indented,
            settings
        ));
    }
}

public class ReferenceData {
    public string Version { get; set; }
    public List<DataItem> Data { get; set; }
}


[CustomJsonSerializable]
public class DataItem {
    public Dictionary<string, string> Item { get; set; }

    public static void WriteJson(JsonWriter writer, DataItem value, JsonSerializer serializer) {
        serializer.Serialize(writer, value.Item);
    }

    public static DataItem ReadJson(JsonReader reader, DataItem existingValue, JsonSerializer serializer) {
        DataItem result = new DataItem();
        result.Item = serializer.Deserialize<Dictionary<string, string>>(reader);
        return result;
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class CustomJsonSerializableAttribute : Attribute {
    public readonly string Read;
    public readonly string Write;

    public CustomJsonSerializableAttribute()
        : this(null, null) {
    }

    public CustomJsonSerializableAttribute(string read, string write) {
        this.Read = read;
        this.Write = write;
    }
}

public class CustomJsonSerializableConverter : JsonConverter {
    public override bool CanConvert(Type objectType) {
        return objectType.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false) != null;
    }

    public override bool CanWrite {
        get {
            return true;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        if(value != null) {
            var t = value.GetType();
            var attr = (CustomJsonSerializableAttribute)t.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false);
            var @delegate = t.GetMethod(attr.Write ?? "WriteJson", new Type[] { typeof(JsonWriter), t, typeof(JsonSerializer) });
            @delegate.Invoke(null, new object[] { writer, value, serializer });
        } else {
            serializer.Serialize(writer, null);
        }
    }

    public override bool CanRead {
        get {
            return true;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var t = existingValue.GetType();
        var attr = (CustomJsonSerializableAttribute)t.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false);
        var @delegate = t.GetMethod(attr.Read ?? "ReadJson", new Type[] { typeof(JsonReader), t, typeof(JsonSerializer) });
        return @delegate.Invoke(null, new object[] { reader, existingValue, serializer });
    }
}