如何以特定顺序序列化和反序列化具有重复 属性 名称的 JSON 对象?
How to serialize and deserialize a JSON object with duplicate property names in a specific order?
我需要创建一个 C# class 来匹配这个 json 并带有这样的确切括号。
{
"data": {
"a": "4",
"b": "2",
"c": "3",
"a": "444",
},
}
System.Collections.Generic.Dictionary<string, string>
做到了,但它不允许使用相同的密钥进行多次输入,所以这样是行不通的。
List<T>
与自定义数据 class、字符串 [2]、元组或 valueTuples 或 KeyValuePair<string, string>
创建不同的 json,其中每个条目都获得“item1”、“ item1" 或不同的括号。
如何反序列化和序列化这个 JSON?这是我必须支持的客户“标准”。
虽然在技术上没有畸形,JSON 具有重复 属性 名称的对象被最近的 JSON RFC 不推荐,RFC 8259:
An object structure is represented as a pair of curly brackets surrounding zero or more name/value pairs (or members)...
An object whose names are all unique is interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. When the names within an object are not unique, the behavior of software that receives such an object is unpredictable. Many implementations report the last name/value pair only. Other implementations report an error or fail to parse the object, and some implementations report all of the name/value pairs, including duplicates.
您可能希望向您的客户建议另一种 JSON 格式,例如单个键值对对象的数组。
也就是说,如果您必须序列化和反序列化具有重复属性的对象,Json.NET将不会这样做的框,你将不得不创建一个 custom JsonConverter
来手动完成。由于 JSON 对象的值都是同一类型(这里是字符串),您可以绑定到 List<KeyValuePair<string, string>>
.
首先定义如下模型:
public class Model
{
[JsonConverter(typeof(KeyValueListAsObjectConverter<string>))]
public List<KeyValuePair<string, string>> data { get; } = new ();
}
以及以下泛型 JsonConverter<List<KeyValuePair<string, TValue>>>
:
public class KeyValueListAsObjectConverter<TValue> : JsonConverter<List<KeyValuePair<string, TValue>>>
{
public override List<KeyValuePair<string, TValue>> ReadJson(JsonReader reader, Type objectType, List<KeyValuePair<string, TValue>> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
return null;
reader.AssertTokenType(JsonToken.StartObject);
var list = existingValue ?? (List<KeyValuePair<string, TValue>>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndObject)
{
var name = (string)reader.AssertTokenType(JsonToken.PropertyName).Value;
var value = serializer.Deserialize<TValue>(reader.ReadToContentAndAssert());
list.Add(new KeyValuePair<string, TValue>(name, value));
}
return list;
}
public override void WriteJson(JsonWriter writer, List<KeyValuePair<string, TValue>> value, JsonSerializer serializer)
{
writer.WriteStartObject();
foreach (var pair in value)
{
writer.WritePropertyName(pair.Key);
serializer.Serialize(writer, pair.Value);
}
writer.WriteEndObject();
}
}
public static partial class JsonExtensions
{
public static JsonReader AssertTokenType(this JsonReader reader, JsonToken tokenType) =>
reader.TokenType == tokenType ? reader : throw new JsonSerializationException(string.Format("Unexpected token {0}, expected {1}", reader.TokenType, tokenType));
public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
reader.ReadAndAssert().MoveToContentAndAssert();
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
您将能够反序列化和重新序列化问题中显示的 JSON。
演示 fiddle here.
我需要创建一个 C# class 来匹配这个 json 并带有这样的确切括号。
{
"data": {
"a": "4",
"b": "2",
"c": "3",
"a": "444",
},
}
System.Collections.Generic.Dictionary<string, string>
做到了,但它不允许使用相同的密钥进行多次输入,所以这样是行不通的。
List<T>
与自定义数据 class、字符串 [2]、元组或 valueTuples 或 KeyValuePair<string, string>
创建不同的 json,其中每个条目都获得“item1”、“ item1" 或不同的括号。
如何反序列化和序列化这个 JSON?这是我必须支持的客户“标准”。
虽然在技术上没有畸形,JSON 具有重复 属性 名称的对象被最近的 JSON RFC 不推荐,RFC 8259:
An object structure is represented as a pair of curly brackets surrounding zero or more name/value pairs (or members)...
An object whose names are all unique is interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. When the names within an object are not unique, the behavior of software that receives such an object is unpredictable. Many implementations report the last name/value pair only. Other implementations report an error or fail to parse the object, and some implementations report all of the name/value pairs, including duplicates.
您可能希望向您的客户建议另一种 JSON 格式,例如单个键值对对象的数组。
也就是说,如果您必须序列化和反序列化具有重复属性的对象,Json.NET将不会这样做的框,你将不得不创建一个 custom JsonConverter
来手动完成。由于 JSON 对象的值都是同一类型(这里是字符串),您可以绑定到 List<KeyValuePair<string, string>>
.
首先定义如下模型:
public class Model
{
[JsonConverter(typeof(KeyValueListAsObjectConverter<string>))]
public List<KeyValuePair<string, string>> data { get; } = new ();
}
以及以下泛型 JsonConverter<List<KeyValuePair<string, TValue>>>
:
public class KeyValueListAsObjectConverter<TValue> : JsonConverter<List<KeyValuePair<string, TValue>>>
{
public override List<KeyValuePair<string, TValue>> ReadJson(JsonReader reader, Type objectType, List<KeyValuePair<string, TValue>> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
return null;
reader.AssertTokenType(JsonToken.StartObject);
var list = existingValue ?? (List<KeyValuePair<string, TValue>>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndObject)
{
var name = (string)reader.AssertTokenType(JsonToken.PropertyName).Value;
var value = serializer.Deserialize<TValue>(reader.ReadToContentAndAssert());
list.Add(new KeyValuePair<string, TValue>(name, value));
}
return list;
}
public override void WriteJson(JsonWriter writer, List<KeyValuePair<string, TValue>> value, JsonSerializer serializer)
{
writer.WriteStartObject();
foreach (var pair in value)
{
writer.WritePropertyName(pair.Key);
serializer.Serialize(writer, pair.Value);
}
writer.WriteEndObject();
}
}
public static partial class JsonExtensions
{
public static JsonReader AssertTokenType(this JsonReader reader, JsonToken tokenType) =>
reader.TokenType == tokenType ? reader : throw new JsonSerializationException(string.Format("Unexpected token {0}, expected {1}", reader.TokenType, tokenType));
public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
reader.ReadAndAssert().MoveToContentAndAssert();
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
您将能够反序列化和重新序列化问题中显示的 JSON。
演示 fiddle here.