【问题标题】:Creating json object with duplicate keys in C#在 C# 中创建具有重复键的 json 对象
【发布时间】:2020-09-22 16:54:33
【问题描述】:

我通过在 C# 中序列化一个对象(使用 Newtonsoft)来创建一个 json 字符串以传递给第三方图表库,因此无法控制我需要创建的结构。该结构需要一个具有重复键的对象,例如;

{ "color": "dd3333",
  "linewidth": 2,
  "dataset": [ 3,4,5,6 ],
  "dataset": [ 5,6,7,8]
}

我正在努力获得我想要的输出。我正在使用字典,但刚刚遇到了对重复键的需求,这破坏了这一点。我已经查看了创建自己的对象以支持重复键(从这些建议 Duplicate keys in .NET dictionaries? 开始),但仍在努力让它们序列化为我需要的格式。

非常欢迎任何建议!

【问题讨论】:

  • 那将是无效的 JSON。主要的 JSON 序列化程序不会生成它。键必须是唯一的。如果可以,重新定义它以使用数组数组:"datasets": [[ 3,4,5,6 ], [ 5,6,7,8 ]] 此外,严格的 JSON 合规性需要引用的键名。
  • 我建议不要这样做。根据RFC 8259对象中的名称应该是唯一的。。如果你真的需要这个,你需要为包含的类创建你自己的自定义JsonConverter。重复键的自定义解析(非序列化)示例如下:How to deserialize JSON with duplicate property names in the same object
  • 感谢您对不在引号中的名称发表评论,这只是我的错误,他们应该是。我已经编辑了这个问题。正如我上面所说,我在提供这种结构方面别无选择,我正在向第三方应用程序提供数据,这就是定义的结构。我同意这并不理想,但是嘿嘿,我坚持下去。至于它是否是有效的 JSON,这似乎还有待商榷。一个很好的讨论在这里stackoverflow.com/questions/21832701/…
  • 感谢 cmets 反序列化,我已经看到了。不幸的是我想序列化对象,第三方应用程序反序列化,所以不是我的问题!
  • @Nick 讨论(2014 年 2 月)来自 RFC 8259(2017 年 12 月)之前声明 “对象中的名称应该是唯一的。” 你使用什么库?要求违反明确规定的标准是糟糕的设计。

标签: c# json .net json.net generic-collections


【解决方案1】:

为了解决这个问题,我创建了一个接受重复键的字典对象(从 Duplicate keys in .NET dictionaries? 复制),并添加了一个 JsonConverter 来控制对象的序列化方式;

  public class MultiMap<TKey, TValue>
  {
    private readonly Dictionary<TKey, IList<TValue>> storage;

    public MultiMap()
    {
      storage = new Dictionary<TKey, IList<TValue>>();
    }

    public void Add(TKey key, TValue value)
    {
      if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>());
      storage[key].Add(value);
    }

    public IEnumerable<TKey> Keys
    {
      get { return storage.Keys; }
    }

    public bool ContainsKey(TKey key)
    {
      return storage.ContainsKey(key);
    }

    public IList<TValue> this[TKey key]
    {
      get
      {
        if (!storage.ContainsKey(key))
          throw new KeyNotFoundException(
              string.Format(
                  "The given key {0} was not found in the collection.", key));
        return storage[key];
      }
    }
  }

JsonConverter 对象如下(我不需要它,所以我没有费心读取它,但它很容易实现);

public class MultiMapJsonConverter<TKey, TValue> : JsonConverter
  {
    public override bool CanConvert(Type objectType)
    {
      return objectType == typeof(MultiMap<TKey, TValue>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
      throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
      writer.WriteStartObject();
      MultiMap<TKey, TValue> m = (MultiMap<TKey, TValue>)value;

      foreach (TKey key in m.Keys)
      {
        foreach (TValue val in m[key])
        {
          writer.WritePropertyName(key.ToString());
          JToken.FromObject(val).WriteTo(writer);
        }
      }
      writer.WriteEndObject();
    }
  }

有了这个定义,下面的代码;

var mm = new MultiMap<string, object>();
mm.Add("color", "dd3333");
mm.Add("linewidth", 2);
mm.Add("dataset", new int[] { 3,4,5,6 });
mm.Add("dataset", new int[] { 5,6,7,8 });
var json = JsonConvert.SerializeObject(mm, new JsonConverter[] { new MultiMapJsonConverter<string, object>() });

给我 json 输出;

{"color":"dd3333","linewidth":2,"dataset":[3,4,5,6],"dataset":[5,6,7,8]}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-12
    • 2017-11-30
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2014-08-16
    相关资源
    最近更新 更多