将字典序列化为数组(键值对)

时间:2012-10-05 17:39:35

标签: c# json.net

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

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

哪个好。从环顾四周看似乎是大多数人想要的东西。但是,在这种特殊情况下,我想在我的Dictionary<k,v>和数组格式之间进行序列化,而不是

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

使用现有的字段类型有一种简单的方法吗?是否有我可以注释的属性?

5 个答案:

答案 0 :(得分:33)

另一种方法是使用自定义ContractResolver。这样,每次序列化时,您都不必子类Dictionary<K,V>,也不必应用转换,如其他答案所示。

以下解析程序将导致所有词典序列化为具有“键”和“值”属性的对象数组:

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

答案 1 :(得分:24)

啊,事实证明这和我希望的一样简单。我的Dictionary<k,v>已经被子类化,我发现我可以使用[JsonArrayAttribute]对其进行注释。这给了我完全符合我需要的格式;

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

答案 2 :(得分:12)

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

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小提琴链接:https://dotnetfiddle.net/LhisVW

答案 3 :(得分:1)

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

答案 4 :(得分:0)

我不确定为什么,但是上面列出的Brian Brians定制的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);
        }
    }