2010-07-25 110 views
78

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

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

+0

只是出于好奇,为什么你会在意吗? – 2012-07-03 10:41:44

+3

我想他可能会首先显示ID字段(或类似字段),然后是所有其他字段。对于最终用户而言,这比对以A..I – michaelAngelo 2012-11-14 14:53:54

+1

开头的字段之后的字符进行查找更友好.JSON属性被定义为无序。我认为在序列化过程中强制执行某个OUTPUT命令是绝对没问题的(也许是为了目击JSON),但是在反序列化的任何特定顺序上创建DEPENDENCY将是一个错误的决定。 – DaBlick 2015-06-30 12:58:28

回答

-1

我随后经由反射JsonConvert.SerializeObject(key)方法调用(其中键是一个IList),发现JsonSerializerInternalWriter.SerializeList被调用。它需要一个列表,并通过

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

其中值是IList的参数带来的遍历。

简短的回答是......不,没有内置的方法来设置字段的顺序列在JSON字符串中。

+9

简短的回答,但可能过时。看看史蒂夫的回答(由詹姆斯牛顿王支持) – 2015-08-01 13:41:20

-3

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

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

+0

这只适用于“在线”传输,而不适用于另一端的消耗。一旦反序列化,基本上我并不期望命令持续存在。 – 2010-07-25 21:03:45

+0

你在说什么? JSON是一种允许对象序列化/反序列化的格式。在OOP的对象字段中没有概念*顺序*。 – 2010-07-25 21:04:50

+9

@Darin - 但是在序列化中有一个命令。 “{id:1,name:'John'}”and“{name:'John',id:1}”与* strings *不同,这就是我所关心的。当然,反序列化时对象是等价的。 – 2010-07-25 21:09:21

88

您可以通过执行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); 
+1

完美地为我工作 – michaelAngelo 2012-11-14 14:54:26

+0

谢谢!我正在找那个! – esskar 2013-03-16 18:15:42

+3

这非常有用(+1),但有一点需要注意:它出现的字典序列化不会使用此CreateProperties自定义。他们序列化好,但不会最终排序。我假设有一种不同的方式来定制字典的序列化,但我还没有找到它。 – solublefish 2015-03-06 19:46:12

0

以下递归方法使用反射来对现有的JObject实例上的内部令牌列表进行排序,而不是创建一个br和新的排序对象图。此代码依赖于内部的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); 
    } 
} 
168

支持的方法是使用上要设置订单的类属性的属性JsonPropertyRead the JsonPropertyAttribute order documentation for more information

通过JsonPropertyOrder值,序列化程序将处理其余的。

[JsonProperty(Order = 1)] 

这是非常相似的

DataMember(Order = 1) 
System.Runtime.Serialization

+61

使用'JsonPropertyAttribute'的'Order'属性可以控制字段序列化/反序列化的顺序。但是,如果您在所有其他属性上设置的订单大于1,则仅将订单设置为1。默认情况下,没有订单设置的任何属性将被赋予-1的顺序。所以你必须给所有序列化的属性和顺序,或者将你的第一项设置为-2。 – 2014-02-25 11:23:27

+0

这个解决方案对我来说非常合适。^5 – 2015-07-16 21:58:33

+1

它适用于序列化,但是在反序列化中没有考虑该顺序。根据文档,order属性用于序列化和反序列化。有没有解决方法? – cangosta 2015-12-21 18:46:36

10

在我的情况下,Mattias的答案没有奏效。 CreateProperties方法从未被调用过。

在对Newtonsoft.Json内部进行了一些调试之后,我想出了另一种解决方案。

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; 
    } 
} 
+0

这是使用字典时所需的修复方法。 – noocyte 2015-06-03 08:39:38

0

实际上,因为我的目标已经是一个JObject,我用以下解决方案:

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)); 
7

在我的情况niaher的解决方案做了不工作,因为它没有处理数组中的对象。

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

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; 
     } 
    } 
} 
0

如果你控制(即写入)类,把属性按字母顺序排列,他们将按照字母顺序序列化时JsonConvert.SerializeObject()被调用。

2

查理指出,可以一定程度上受到的类本身订货属性控制JSON属性的排序。不幸的是,这种方法不适用于从基类继承的属性。基类属性将按照它们在代码中的布局进行排序,但会显示在基类属性之前。

而且任何人都知道为什么,你可能想按字母顺序排列JSON性能,它是一个整体更容易与原始JSON文件的工作,特别是对类有很多的属性,如果他们是有序的。