Порядок использования сериализованных полей JSON.NET
есть ли способ указать порядок полей в сериализованном объекте JSON с помощью JSON.NET?
было бы достаточно указать, что одно поле всегда появляется первым.
11 ответов:
я следовал
JsonConvert.SerializeObject(key)
вызов метода через отражение (где ключ был IList) и обнаружил, что JsonSerializerInternalWriter.SerializeList получает вызов. Он принимает список и петли через via
for (int i = 0; i < values.Count; i++) { ...
где значения-это введенный параметр IList.
короткий ответ is...No, нет встроенного способа установить порядок, в котором поля перечислены в строке JSON.
поддерживаемый способ-использовать
JsonProperty
атрибут для свойств класса, для которых вы хотите установить порядок. прочитайте документацию по заказу JsonPropertyAttribute для получения дополнительной информации.передать
JsonProperty
anOrder
значение и сериализатор позаботятся об остальном.[JsonProperty(Order = 1)]
это очень похоже на
DataMember(Order = 1)
на
System.Runtime.Serialization
дней.
вы можете фактически контролировать порядок, реализуя
IContractResolver
или переопределениеDefaultContractResolver
' sCreateProperties
метод.вот пример моей простой реализации
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
внутренности, я придумал другое решение.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; } }
в моем случае решение ниахера не работало, потому что оно не обрабатывало объекты в массивах.
на основе его решения это то, что я придумал
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, упорядочивая свойства в самом классе. К сожалению, этот подход не работает для свойств, унаследованных от базового класса. Свойства базового класса будут упорядочены по мере их размещения в коде, но появятся перед свойствами базового класса.
и для тех, кто задается вопросом, почему вы можете захотеть расположить свойства JSON в алфавитном порядке, гораздо проще работать с файлами raw JSON, особенно для классов с большим количеством свойств, если им прикажут.
следующий рекурсивный метод использует отражение для сортировки внутреннего списка маркеров на существующем
JObject
экземпляр, а не создание совершенно нового отсортированного графа объектов. Этот код полагается на внутренний 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, я использовал следующее решение:
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));
Если вы управляете (т. е. пишете) классом, поместите свойства в алфавитном порядке, и они будут сериализованы в алфавитном порядке, когда
JsonConvert.SerializeObject()
называется.
Если вы хотите глобально настроить свой API с упорядоченными полями, пожалуйста, объедините ответ Маттиаса Нордберга:
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(); } }
мой ответ здесь: