使用JSON.NET序列化字段的顺序

有没有一种方法来指定使用JSON.NET的序列化的JSON对象中的字段的顺序?

指定单个字段总是首先出现就足够了。

我通过reflection(其中键是一个IList)跟随JsonConvert.SerializeObject(key)方法调用,发现JsonSerializerInternalWriter.SerializeList被调用。 它需要一个列表,并通过通过循环

for (int i = 0; i < values.Count; i++) { ...

其中值是引入的IList参数。

简短的答案是…不,没有内置的方式来设置字段在JSONstring中列出的顺序。

支持的方法是在要为其设置顺序的类属性上使用JsonProperty属性。 阅读JsonPropertyAttribute订单文档以获取更多信息 。

JsonProperty传递给一个Order值,序列化器将处理剩下的JsonProperty

  [JsonProperty(Order = 1)] 

这是非常相似的

  DataMember(Order = 1) 

System.Runtime.Serialization天。

实际上你可以通过实现IContractResolver或者重写DefaultContractResolverCreateProperties方法来控制顺序。

下面是我简单实现IContractResolver的一个例子,它按字母顺序排列属性:

 public class OrderedContractResolver : DefaultContractResolver { protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization) { return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList(); } } 

然后设置设置并序列化对象,JSON字段将按字母顺序排列:

 var settings = new JsonSerializerSettings() { ContractResolver = new OrderedContractResolver() }; var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings); 

在我的情况下,马蒂亚斯的答案没有奏效。 CreateProperties方法从未被调用。

在对Newtonsoft.Json内部进行了一些debugging之后,我想出了另一个解决scheme。

 public class JsonUtility { public static string NormalizeJsonString(string json) { // Parse json string into JObject. var parsedObject = JObject.Parse(json); // Sort properties of JObject. var normalizedObject = SortPropertiesAlphabetically(parsedObject); // Serialize JObject . return JsonConvert.SerializeObject(normalizedObject); } private static JObject SortPropertiesAlphabetically(JObject original) { var result = new JObject(); foreach (var property in original.Properties().ToList().OrderBy(p => p.Name)) { var value = property.Value as JObject; if (value != null) { value = SortPropertiesAlphabetically(value); result.Add(property.Name, value); } else { result.Add(property.Name, property.Value); } } return result; } } 

在我的情况下,niaher的解决scheme不起作用,因为它不处理数组中的对象。

基于他的解决scheme,这是我想出了

 public static class JsonUtility { public static string NormalizeJsonString(string json) { JToken parsed = JToken.Parse(json); JToken normalized = NormalizeToken(parsed); return JsonConvert.SerializeObject(normalized); } private static JToken NormalizeToken(JToken token) { JObject o; JArray array; if ((o = token as JObject) != null) { List<JProperty> orderedProperties = new List<JProperty>(o.Properties()); orderedProperties.Sort(delegate(JProperty x, JProperty y) { return x.Name.CompareTo(y.Name); }); JObject normalized = new JObject(); foreach (JProperty property in orderedProperties) { normalized.Add(property.Name, NormalizeToken(property.Value)); } return normalized; } else if ((array = token as JArray) != null) { for (int i = 0; i < array.Count; i++) { array[i] = NormalizeToken(array[i]); } return array; } else { return token; } } } 

JSON格式没有字段顺序,所以定义一个顺序是没有意义的。

{ id: 1, name: 'John' }相当于{ name: 'John', id: 1 } (都表示一个严格等价的对象实例)

以下recursion方法使用reflection来对现有JObject实例上的内部令牌列表进行sorting,而不是创build全新的sorting对象图。 这段代码依赖于内部的Json.NET实现细节,不应该在生产中使用。

 void SortProperties(JToken token) { var obj = token as JObject; if (obj != null) { var props = typeof (JObject) .GetField("_properties", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(obj); var items = typeof (Collection<JToken>) .GetField("items", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(props); ArrayList.Adapter((IList) items) .Sort(new ComparisonComparer( (x, y) => { var xProp = x as JProperty; var yProp = y as JProperty; return xProp != null && yProp != null ? string.Compare(xProp.Name, yProp.Name) : 0; })); } foreach (var child in token.Children()) { SortProperties(child); } } 

其实,因为我的对象已经是一个JObject,我使用了以下的解决scheme:

 public class SortedJObject : JObject { public SortedJObject(JObject other) { var pairs = new List<KeyValuePair<string, JToken>>(); foreach (var pair in other) { pairs.Add(pair); } pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value); } } 

然后像这样使用它:

 string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject)); 

正如Charlie指出的那样,您可以通过sorting类中的属性来控制JSON属性的sorting。 不幸的是,这种方法不适用于从基类inheritance的属性。 基类属性将按照它们在代码中的布局进行sorting,但会显示在基类属性之前。

而对于任何人想知道为什么你可能希望按字母sortingJSON属性,使用原始JSON文件,特别是对于具有许多属性的类(如果它们是有序的),更容易一些。

如果你控制(即写)类,按字母顺序放置属性,当JsonConvert.SerializeObject()被调用时,它们将按字母顺序序列化。