【问题标题】:Serialize dictionary as array (of key value pairs)将字典序列化为数组(键值对)
【发布时间】:2012-10-05 17:39:35
【问题描述】:

Json.Net 通常将Dictionary<k,v> 序列化为集合;

"MyDict": {
  "Apples": {
    "Taste": 1341181398,
    "Title": "Granny Smith",
  },
  "Oranges": {
    "Taste": 9999999999,
    "Title": "Coxes Pippin",
  },
 }

这很棒。从 SO 上环顾四周,这似乎是大多数人想要的。但是,在这种特殊情况下,我想在我的 Dictionary<k,v> 和数组格式之间进行序列化;

"MyDict": [
    "k": "Apples",
    "v": {
        "Taste": 1341181398,
        "Title": "Granny Smith",
    }
  },
    "k:": "Oranges",
    "v:": {
        "Taste": 9999999999,
        "Title": "Coxes Pippin",
    }
  },
]

有没有一种简单的方法可以用我现有的字段类型来做到这一点?例如,有没有我可以注释的属性?

【问题讨论】:

  • 您可能在所需输出的示例中缺少一些括号和大括号。

标签: c# json.net


【解决方案1】:

实现此目的的另一种方法是使用自定义ContractResolver。这样您就不必像其他答案中所建议的那样,在每次序列化时继承 Dictionary<K,V> 或应用转换。

以下解析器将导致所有字典序列化为具有“Key”和“Value”属性的对象数组:

class DictionaryAsArrayResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) || 
           (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>))))
        {
            return base.CreateArrayContract(objectType);
        }

        return base.CreateContract(objectType);
    }
}

要使用解析器,请将其添加到您的 JsonSerializerSettings,然后将设置传递给 JsonConvert.SerializeObject(),如下所示:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new DictionaryAsArrayResolver();

string json = JsonConvert.SerializeObject(obj, settings);

这是working demo

【讨论】:

  • 为序列化工作,现在如何反序列化同一个对象
  • @MSTdev 同样的想法,使用JsonConvert.DeserializeObject 并确保将JsonSerializerSettings 与解析器一起传递给该方法。我更新了小提琴来演示。
  • @BrianRogers 请查看我的详细问题stackoverflow.com/questions/32473308/…
  • 如果我只想转换 Dictionary 怎么办?将 IDictionary 都更改为 IDictionary?
【解决方案2】:

啊,事实证明这和我希望的一样简单。我的Dictionary&lt;k,v&gt; 已经被子类化了,我发现我可以用[JsonArrayAttribute] 对其进行注释。这正是我需要的格式;

"MyDict": [
  {
    "Key": "Apples",
    "Value": {
        "Taste": 1341181398,
        "Title": "Granny Smith",
    }
  },
  {
    "Key:": "Oranges",
    "Value:": {
        "Taste": 9999999999,
        "Title": "Coxes Pippin",
    }
  },
]

【讨论】:

  • 有没有办法通过 Json.NET 配置来展平 Key 和 Value 属性(成为顶级数组中对象的一个​​属性)?
【解决方案3】:

对于这个例子,我将使用字典:

var myDict = new Dictionary<string,string>() { 
    {"a","123"}, 
    {"b","234"}, 
    {"c","345"} 
};

将(使用Newtonsoft.Json.JsonConvert.SerializeObject(myDict))序列化为:

{"a":"123","b":"234","c":"345"}

您可以使用 LINQ 进行转换以创建一个匿名对象,并将其序列化:

 var myDictTransformed = from key in myDict.Keys
                         select new { k = key, v = myDict[key] };

或者你可以使用一个真实的对象

class MyDictEntry 
{
    public string k { get; set; }
    public string v { get; set; }
}

以及上述或替代 LINQ 语法:

var myDictTransformed = myDict.Keys.AsEnumerable()
                        .Select(key => new MyDictEntry{ 
                            k = key, 
                            v = myDict[key] 
                        });

无论哪种方式,这都会序列化为:

[
  {"k":"a", "v":"123"},
  {"k":"b", "v":"234"},
  {"k":"c", "v":"345"}
]

.NET Fiddle 链接:https://dotnetfiddle.net/LhisVW

【讨论】:

    【解决方案4】:

    我找到的最简单的解决方案是将您的Dictionary&lt;string, string&gt; 转换为List&lt;KeyValuePair&lt;string, string&gt;&gt;。 JSON.NET 然后将您的List 转换为具有{ Key: 'keyname', Value: 'value' } 形式的对象数组。如果您接受所需的模型更改并且不想子类化您的 Dictionary,这很有效。

    【讨论】:

    • 使用 ToList() 或 ToArray() 扩展方法可以轻松完成。
    【解决方案5】:

    gregmac 的回答很有帮助,但不太奏效。以下是相同的想法......没有双关语。

    var dictionaryTransformed = dictionary.Select(item => item.Key).Select(i => 
                            new {Key = i, Value = dictionary[i] });
    

    当然

    var dictionaryTransformed = dictionary.Select(item => 
                            new {item.Key, Value = dictionary[item.Key] });
    

    然后转json

    var json = (new JavaScriptSerializer()).Serialize( 
                            new { Container = dictionaryTransformed.ToArray() } )
    

    【讨论】:

      【解决方案6】:

      我不确定为什么,但上面列出的 Brian Rogers 的自定义 ContractResolver 对我不起作用。它似乎在内部某个地方陷入了无限循环。可能是由于我的 json.net 设置的其他部分。

      无论如何-这个解决方法对我有用。

      public interface IStrongIdentifier
          {
              string StringValue { get; set; }
          }
      
      public class StrongIdentifierKeyedDictionaryWrapper<TKey, TValue> : Dictionary<string, TValue>
              where TKey : IStrongIdentifier
          {
              public void Add(TKey key, TValue value)
              {
                  base.Add(key.StringValue, value);
              }
      
              public void Remove(TKey key)
              {
                  base.Remove(key.StringValue);
              }
      
              public TValue this[TKey index]
              {
                  get => base[index.StringValue];
                  set => base[index.StringValue] = value;
              }
      
              public bool ContainsKey(TKey key)
              {
                  return base.ContainsKey(key.StringValue);
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-23
        相关资源
        最近更新 更多