C# 将字典序列化为数组(键值对)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12751354/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Serialize dictionary as array (of key value pairs)
提问by cirrus
Json.Net typically serializes a Dictionary<k,v>into a collection;
Json.Net 通常将 a 序列Dictionary<k,v>化为一个集合;
"MyDict": {
"Apples": {
"Taste": 1341181398,
"Title": "Granny Smith",
},
"Oranges": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
},
}
Which is great. And from looking around on SO it seems to be what most people want. However, in this particular case, I want to serialize between my Dictionary<k,v>and the Array format instead;
这很棒。环顾四周,这似乎是大多数人想要的。但是,在这种特殊情况下,我想在 myDictionary<k,v>和 Array 格式之间进行序列化;
"MyDict": [
"k": "Apples",
"v": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
"k:": "Oranges",
"v:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
Is there an easy way to do this with my existing field type? Is there an attribute I can annotate for instance?
有没有一种简单的方法可以用我现有的字段类型来做到这一点?例如,是否有我可以注释的属性?
采纳答案by cirrus
Ah, it turns out this is as straightforward as I'd hoped. My Dictionary<k,v>is subclassed already and I found that I can annotate it with [JsonArrayAttribute]. That gives me exactly the format I need;
啊,事实证明这和我希望的一样简单。MyDictionary<k,v>已经被子类化了,我发现我可以用[JsonArrayAttribute]. 这正是我需要的格式;
"MyDict": [
{
"Key": "Apples",
"Value": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
{
"Key:": "Oranges",
"Value:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
回答by gregmac
For this example, I'll use the dictonary:
对于这个例子,我将使用字典:
var myDict = new Dictionary<string,string>() {
{"a","123"},
{"b","234"},
{"c","345"}
};
which serializes (with Newtonsoft.Json.JsonConvert.SerializeObject(myDict)) to:
序列化(与Newtonsoft.Json.JsonConvert.SerializeObject(myDict))到:
{"a":"123","b":"234","c":"345"}
You could do a transform using LINQ to create an anonymous object, and serialize that:
您可以使用 LINQ 进行转换以创建匿名对象,并对其进行序列化:
var myDictTransformed = from key in myDict.Keys
select new { k = key, v = myDict[key] };
Or you could use a real object
或者你可以使用一个真实的对象
class MyDictEntry
{
public string k { get; set; }
public string v { get; set; }
}
and either the above or the alternative LINQ syntax:
以及上述或替代的 LINQ 语法:
var myDictTransformed = myDict.Keys.AsEnumerable()
.Select(key => new MyDictEntry{
k = key,
v = myDict[key]
});
Either way, this serializes to:
无论哪种方式,这都会序列化为:
[
{"k":"a", "v":"123"},
{"k":"b", "v":"234"},
{"k":"c", "v":"345"}
]
.NET Fiddle link: https://dotnetfiddle.net/LhisVW
.NET Fiddle 链接:https: //dotnetfiddle.net/LhisVW
回答by ccook
gregmac's answer was helpful, but didn't quite work. The following is the same idea... without the puns.
gregmac 的回答很有帮助,但不太奏效。以下是相同的想法......没有双关语。
var dictionaryTransformed = dictionary.Select(item => item.Key).Select(i =>
new {Key = i, Value = dictionary[i] });
or of course
或者当然
var dictionaryTransformed = dictionary.Select(item =>
new {item.Key, Value = dictionary[item.Key] });
Then to json
然后到json
var json = (new JavaScriptSerializer()).Serialize(
new { Container = dictionaryTransformed.ToArray() } )
回答by Brian Rogers
Another way to accomplish this is to use a custom ContractResolver. That way you do not have to subclass Dictionary<K,V>nor apply a transform each time you serialize, as suggested in other answers.
实现此目的的另一种方法是使用自定义ContractResolver. 这样您就不必在Dictionary<K,V>每次序列化时都进行子类化或应用转换,正如其他答案中所建议的那样。
The following resolver will cause ALL dictionaries to be serialized as an array of objects with "Key" and "Value" properties:
以下解析器将导致所有字典序列化为具有“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);
}
}
To use the resolver, add it to your JsonSerializerSettings, then pass the settings to JsonConvert.SerializeObject()like this:
要使用解析器,请将其添加到您的JsonSerializerSettings,然后JsonConvert.SerializeObject()像这样传递设置:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new DictionaryAsArrayResolver();
string json = JsonConvert.SerializeObject(obj, settings);
Here is a working demo.
这是一个工作演示。
回答by Swoogan
The simplest solution I found is to convert your Dictionary<string, string>to a List<KeyValuePair<string, string>>. JSON.NET then converts your Listinto an array of objects with the form { Key: 'keyname', Value: 'value' }. This works well if you accept the required model change and don't want to subclass your Dictionary.
我找到的最简单的解决方案是将您Dictionary<string, string>的List<KeyValuePair<string, string>>. 然后 JSON.NET 将您List的对象转换为格式为 的对象数组{ Key: 'keyname', Value: 'value' }。如果您接受所需的模型更改并且不想将您的Dictionary.
回答by Damien Sawyer
I'm not exactly sure why, but the custom ContractResolver by Brian Rogers listed above didn't work for me. It seemed to get into an endless loop somewhere internally. Possibly due to other parts of my json.net setup.
我不确定为什么,但上面列出的 Brian Rogers 的自定义 ContractResolver 对我不起作用。它似乎在内部某处陷入了无限循环。可能是由于我的 json.net 设置的其他部分。
Anyway - this workaround did the trick for me.
无论如何 - 这个解决方法对我有用。
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);
}
}

