c#中使用newtonsoft实现JSON序列化

本文关键字:实现 JSON 序列化 newtonsoft | 更新日期: 2023-09-27 17:52:50

我有以下模型结构:

 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"
      }
   ]
}

c#中使用newtonsoft实现JSON序列化

如果使用Json,则不需要嵌套的泛型集合。NET 5.0 release 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

如果你这样做,结果将是你所期望的;

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设置更简单,更容易返回并且更显式:

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

您可以实现以下自定义行为:

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 });
    }
}