myślę, że prawdopodobnie jest zainteresowany wyświetleniem najpierw pola ID (lub podobnego), a następnie wszystkich innych pól. jest to bardziej przyjazne dla użytkowników końcowych niż szukanie go po polach zaczynających się na literę A..I
Michael Bahig 14.12
3
Właściwości JSON są zdefiniowane jako nieuporządkowane. Myślę, że wymuszenie określonej kolejności WYJŚCIA podczas serializacji (być może w celu obejrzenia JSON) jest absolutnie w porządku, ale utworzenie ZALEŻNOŚCI od konkretnego zamówienia podczas deserializacji byłoby złą decyzją.
DaBlick
5
Kilka ważnych powodów: (1) udawanie właściwości „$ type”, która musi być pierwszą właściwością w JSON, (2) próba wygenerowania JSON, który kompresuje jak najwięcej
Stephen Chung,
4
Innym powodem może być (3) reprezentacja kanoniczna, która używa składni JSON - ten sam obiekt musi mieć gwarancję, że wygeneruje ten sam ciąg JSON. Warunkiem koniecznym jest deterministyczny porządek atrybutów.
MarkusSchaber
2
Kevin, czy możesz zaktualizować zaakceptowaną odpowiedź na to pytanie?
Millie Smith
Odpowiedzi:
255
Obsługiwanym sposobem jest użycie JsonPropertyatrybutu we właściwościach klasy, dla których chcesz ustawić kolejność. Przeczytaj dokumentację zamówienia JsonPropertyAttribute, aby uzyskać więcej informacji.
Zdać JsonPropertysię Orderwartość i serializer zajmie się resztą.
[JsonProperty(Order=1)]
Jest to bardzo podobne do
DataMember(Order=1)
z System.Runtime.Serializationdni.
Oto ważna uwaga od @ kevin-babcock
... ustawienie kolejności na 1 zadziała tylko wtedy, gdy ustawisz kolejność większą niż 1 dla wszystkich innych właściwości. Domyślnie każda właściwość bez ustawienia Order otrzyma kolejność -1. Musisz więc podać wszystkie zserializowane właściwości i kolejność lub ustawić pierwszy element na -2
Za pomocą Orderwłaściwości JsonPropertyAttributemożna kontrolować kolejność serializacji / deserializacji pól. Jednak ustawienie kolejności na 1 zadziała tylko wtedy, gdy ustawisz kolejność większą niż 1 dla wszystkich innych właściwości. Domyślnie każda właściwość bez ustawienia Order otrzyma kolejność -1. Musisz więc podać wszystkie zserializowane właściwości i kolejność lub ustawić pierwszy element na -2.
Kevin Babcock,
1
Działa w przypadku serializacji, ale kolejność nie jest brana pod uwagę podczas deserializacji. Zgodnie z dokumentacją atrybut order jest używany zarówno do serializacji, jak i deserializacji. Czy jest w pobliżu praca?
cangosta
1
Czy istnieje podobna właściwość dla JavaScriptSerializer.
Shimmy Weitzhandler
4
@cangosta Kolejność deserializacji nie powinna mieć znaczenia .. z wyjątkiem niektórych bardzo „dziwnych” przypadków oczekiwań.
Jest to całkiem pomocne (+1), ale jedno zastrzeżenie: wydaje się, że serializacja słowników nie korzysta z tej personalizacji CreateProperties. Serializują się dobrze, ale nie są sortowane. Zakładam, że istnieje inny sposób dostosowania serializacji słowników, ale go nie znalazłem.
rozpuszczalna ryba
Idealny. Robi to, co chciałem. Dzięki.
Wade Hatler
To świetne rozwiązanie. U mnie zadziałało idealnie, zwłaszcza gdy umieściłem 2 obiekty JSON obok siebie i wyrównałem właściwości.
Vince
16
W moim przypadku odpowiedź Mattiasa nie zadziałała. CreatePropertiesMetoda nie została wywołana.
Po pewnym debugowaniu elementów Newtonsoft.Jsonwewnętrznych wpadłem na inne rozwiązanie.
publicclassJsonUtility{publicstaticstringNormalizeJsonString(string json){// Parse json string into JObject.var parsedObject =JObject.Parse(json);// Sort properties of JObject.var normalizedObject =SortPropertiesAlphabetically(parsedObject);// Serialize JObject .returnJsonConvert.SerializeObject(normalizedObject);}privatestaticJObjectSortPropertiesAlphabetically(JObject original){var result =newJObject();foreach(var property in original.Properties().ToList().OrderBy(p => p.Name)){varvalue= property.ValueasJObject;if(value!=null){value=SortPropertiesAlphabetically(value);
result.Add(property.Name,value);}else{
result.Add(property.Name, property.Value);}}return result;}}
To była wymagana poprawka dla nas podczas korzystania z dyktowania.
noocyte
Zwiększa to narzut dodatkowej deserializacji i serializacji. Dodałem rozwiązanie, które będzie działać dla normalnych klas, słowników i ExpandoObject (dynamiczny obiekt)
Jay Shah
11
W moim przypadku rozwiązanie niaher nie zadziałało, ponieważ nie obsługiwało obiektów w tablicach.
Zwiększa to narzut dodatkowej deserializacji i serializacji.
Jay Shah
Doskonałe rozwiązanie. Dziękuję Ci.
MaYaN
3
Jak zauważył Charlie, możesz w pewnym stopniu kontrolować kolejność właściwości JSON, porządkując właściwości w samej klasie. Niestety to podejście nie działa w przypadku właściwości dziedziczonych z klasy bazowej. Właściwości klasy bazowej zostaną uporządkowane zgodnie z układem w kodzie, ale pojawią się przed właściwościami klasy bazowej.
A dla każdego, kto zastanawia się, dlaczego warto ułożyć alfabetycznie właściwości JSON, praca z surowymi plikami JSON jest o wiele łatwiejsza, szczególnie w przypadku klas z dużą ilością właściwości, jeśli są one uporządkowane.
Czy nie było to domyślne zachowanie kolejności podczas serializacji?
mr5
1
Aby zaoszczędzić komuś kilka straconych minut, pamiętaj, że ta odpowiedź nie działa w przypadku słowników pomimo twierdzenia. CreatePropertiesnie jest wywoływana podczas serializacji słownika. Przeszukałem repozytorium JSON.net, aby sprawdzić, jakie maszyny faktycznie przeglądają wpisy słownika. Nie wiąże się z żadnym overridedostosowaniem do zamówienia. Po prostu pobiera wpisy takie, jakie są z modułu wyliczającego obiektu. Wygląda na to, że muszę skonstruować SortedDictionarylub SortedListzmusić JSON.net do zrobienia tego. Propozycja funkcji zgłoszona: github.com/JamesNK/Newtonsoft.Json/issues/2270
William
2
Jeśli nie chcesz umieszczać JsonPropertyOrderatrybutu na każdej właściwości klasy, bardzo łatwo jest utworzyć własny element ContractResolver ...
Interfejs IContractResolver umożliwia dostosowanie sposobu serializacji i deserializacji obiektów .NET do formatu JSON przez JsonSerializer bez umieszczania atrybutów w klasach.
Lubię to:
privateclassSortedPropertiesContractResolver:DefaultContractResolver{// use a static instance for optimal performancestaticSortedPropertiesContractResolver instance;staticSortedPropertiesContractResolver(){ instance =newSortedPropertiesContractResolver();}publicstaticSortedPropertiesContractResolverInstance{get{return instance;}}protectedoverrideIList<JsonProperty>CreateProperties(Type type,MemberSerialization memberSerialization){var properties =base.CreateProperties(type, memberSerialization);if(properties !=null)return properties.OrderBy(p => p.UnderlyingName).ToList();return properties;}}
Wprowadzić w życie:
var settings =newJsonSerializerSettings{ContractResolver=SortedPropertiesContractResolver.Instance};var json =JsonConvert.SerializeObject(obj,Formatting.Indented, settings);
Poniższa metoda rekurencyjna używa odbicia do sortowania wewnętrznej listy tokenów w istniejącej JObjectinstancji zamiast tworzenia zupełnie nowego posortowanego wykresu obiektów. Ten kod opiera się na wewnętrznych szczegółach implementacji Json.NET i nie powinien być używany w środowisku produkcyjnym.
voidSortProperties(JToken token){var obj = token asJObject;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(newComparisonComparer((x, y)=>{var xProp = x asJProperty;var yProp = y asJProperty;return xProp !=null&& yProp !=null?string.Compare(xProp.Name, yProp.Name):0;}));}foreach(var child in token.Children()){SortProperties(child);}}
Jeśli kontrolujesz (tj. Piszesz) klasę, umieść właściwości w porządku alfabetycznym, a po JsonConvert.SerializeObject()wywołaniu zostaną one serializowane w kolejności alfabetycznej .
Chcę serializować obiekt comblex i zachować kolejność właściwości zgodnie z definicją w kodzie. Nie mogę po prostu dodać, [JsonProperty(Order = 1)]ponieważ sama klasa jest poza moim zakresem.
To rozwiązanie uwzględnia również, że właściwości zdefiniowane w klasie bazowej powinny mieć wyższy priorytet.
Może to nie być kuloodporne, ponieważ nigdzie nie określono, że MetaDataAttributezapewnia prawidłową kolejność, ale wydaje się, że działa. W moim przypadku jest to w porządku. ponieważ chcę zachować czytelność tylko dla człowieka dla automatycznie generowanego pliku konfiguracyjnego.
publicclassPersonWithAge:Person{publicintAge{get;set;}}publicclassPerson{publicstringName{get;set;}}publicstringGetJson(){var thequeen =newPersonWithAge{Name="Elisabeth",Age=Int32.MaxValue};var settings =newJsonSerializerSettings(){ContractResolver=newMetadataTokenContractResolver(),};returnJsonConvert.SerializeObject(
thequeen,Newtonsoft.Json.Formatting.Indented, settings
);}publicclassMetadataTokenContractResolver:DefaultContractResolver{protectedoverrideIList<JsonProperty>CreateProperties(Type type,MemberSerialization memberSerialization){var props = type
.GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic).ToDictionary(k => k.Name, v =>{// first value: declaring typevar classIndex =0;var t = type;while(t != v.DeclaringType){
classIndex++;
t = type.BaseType;}returnTuple.Create(classIndex, v.MetadataToken);});returnbase.CreateProperties(type, memberSerialization).OrderByDescending(p => props[p.PropertyName].Item1).ThenBy(p => props[p.PropertyName].Item1).ToList();}}
Właśnie zobaczyłem głosy przeciw. Zobacz odpowiedź od „Steve” poniżej, aby dowiedzieć się, jak to zrobić.
ORYGINALNY
Śledziłem JsonConvert.SerializeObject(key)wywołanie metody przez odbicie (gdzie klucz był IList) i stwierdziłem, że JsonSerializerInternalWriter.SerializeList jest wywoływana. Pobiera listę i przechodzi przez
for (int i = 0; i < values.Count; i++) { ...
gdzie wartości to wprowadzony parametr IList.
Krótka odpowiedź brzmi ... Nie, nie ma wbudowanego sposobu ustawiania kolejności, w jakiej pola są wyświetlane w ciągu JSON.
@Darin - ale w serializacji jest kolejność. „{id: 1, name: 'John'}” i „{name: 'John', id: 1}” są różne jak ciągi znaków i właśnie na tym mi zależy. Oczywiście obiekty są równoważne po deserializacji.
Kevin Montrose
1
@Darin - nie, nie w tym przypadku. Serializuję coś, a następnie przekazuję to jako ciąg do usługi, która zajmuje się tylko ciągami znaków (bez uwzględnienia formatu JSON) i byłoby wygodne z różnych powodów, aby jedno pole pojawiało się jako pierwsze w ciągu.
Kevin Montrose
1
jest również dobry do testowania, będąc w stanie po prostu spojrzeć na łańcuchy, zamiast konieczności deserializacji.
Steve
9
Stabilna kolejność serializacji jest również przydatna do sprawdzania poprawności pamięci podręcznej. Pobranie sumy kontrolnej łańcucha jest trywialne - nie jest to prawda dla pełnego grafu obiektów.
rozpuszczalna ryba
1
Kolejność serializacji jest również przydatna podczas wykonywania testów jednostkowych, dzięki czemu można łatwo stwierdzić, że oczekiwane i rzeczywiste ciągi odpowiedzi są równe, nawet jeśli kolejność właściwości json jest inna.
Odpowiedzi:
Obsługiwanym sposobem jest użycie
JsonProperty
atrybutu we właściwościach klasy, dla których chcesz ustawić kolejność. Przeczytaj dokumentację zamówienia JsonPropertyAttribute, aby uzyskać więcej informacji.Zdać
JsonProperty
sięOrder
wartość i serializer zajmie się resztą.Jest to bardzo podobne do
z
System.Runtime.Serialization
dni.Oto ważna uwaga od @ kevin-babcock
źródło
Order
właściwościJsonPropertyAttribute
można kontrolować kolejność serializacji / deserializacji pól. Jednak ustawienie kolejności na 1 zadziała tylko wtedy, gdy ustawisz kolejność większą niż 1 dla wszystkich innych właściwości. Domyślnie każda właściwość bez ustawienia Order otrzyma kolejność -1. Musisz więc podać wszystkie zserializowane właściwości i kolejność lub ustawić pierwszy element na -2.JavaScriptSerializer
.Rzeczywiście można kontrolować kolejność poprzez wdrożenie
IContractResolver
lub nadpisanieDefaultContractResolver
„sCreateProperties
metody.Oto przykład mojej prostej implementacji,
IContractResolver
która porządkuje właściwości alfabetycznie:A następnie ustaw ustawienia i serializuj obiekt, a pola JSON będą w kolejności alfabetycznej:
źródło
W moim przypadku odpowiedź Mattiasa nie zadziałała.
CreateProperties
Metoda nie została wywołana.Po pewnym debugowaniu elementów
Newtonsoft.Json
wewnętrznych wpadłem na inne rozwiązanie.źródło
W moim przypadku rozwiązanie niaher nie zadziałało, ponieważ nie obsługiwało obiektów w tablicach.
Na podstawie jego rozwiązania wymyśliłem to
źródło
Jak zauważył Charlie, możesz w pewnym stopniu kontrolować kolejność właściwości JSON, porządkując właściwości w samej klasie. Niestety to podejście nie działa w przypadku właściwości dziedziczonych z klasy bazowej. Właściwości klasy bazowej zostaną uporządkowane zgodnie z układem w kodzie, ale pojawią się przed właściwościami klasy bazowej.
A dla każdego, kto zastanawia się, dlaczego warto ułożyć alfabetycznie właściwości JSON, praca z surowymi plikami JSON jest o wiele łatwiejsza, szczególnie w przypadku klas z dużą ilością właściwości, jeśli są one uporządkowane.
źródło
Będzie to działać również dla normalnych klas, słowników i ExpandoObject (obiektu dynamicznego).
źródło
CreateProperties
nie jest wywoływana podczas serializacji słownika. Przeszukałem repozytorium JSON.net, aby sprawdzić, jakie maszyny faktycznie przeglądają wpisy słownika. Nie wiąże się z żadnymoverride
dostosowaniem do zamówienia. Po prostu pobiera wpisy takie, jakie są z modułu wyliczającego obiektu. Wygląda na to, że muszę skonstruowaćSortedDictionary
lubSortedList
zmusić JSON.net do zrobienia tego. Propozycja funkcji zgłoszona: github.com/JamesNK/Newtonsoft.Json/issues/2270Jeśli nie chcesz umieszczać
JsonProperty
Order
atrybutu na każdej właściwości klasy, bardzo łatwo jest utworzyć własny element ContractResolver ...Lubię to:
Wprowadzić w życie:
źródło
Poniższa metoda rekurencyjna używa odbicia do sortowania wewnętrznej listy tokenów w istniejącej
JObject
instancji zamiast tworzenia zupełnie nowego posortowanego wykresu obiektów. Ten kod opiera się na wewnętrznych szczegółach implementacji Json.NET i nie powinien być używany w środowisku produkcyjnym.źródło
Właściwie, ponieważ mój Object był już JObject, zastosowałem następujące rozwiązanie:
a następnie użyj tego w ten sposób:
źródło
Jeśli kontrolujesz (tj. Piszesz) klasę, umieść właściwości w porządku alfabetycznym, a po
JsonConvert.SerializeObject()
wywołaniu zostaną one serializowane w kolejności alfabetycznej .źródło
Chcę serializować obiekt comblex i zachować kolejność właściwości zgodnie z definicją w kodzie. Nie mogę po prostu dodać,
[JsonProperty(Order = 1)]
ponieważ sama klasa jest poza moim zakresem.To rozwiązanie uwzględnia również, że właściwości zdefiniowane w klasie bazowej powinny mieć wyższy priorytet.
Może to nie być kuloodporne, ponieważ nigdzie nie określono, że
MetaDataAttribute
zapewnia prawidłową kolejność, ale wydaje się, że działa. W moim przypadku jest to w porządku. ponieważ chcę zachować czytelność tylko dla człowieka dla automatycznie generowanego pliku konfiguracyjnego.źródło
Jeśli chcesz globalnie skonfigurować swoje API z uporządkowanymi polami, połącz odpowiedź Mattiasa Nordberga:
z moją odpowiedzią tutaj:
Jak zmusić interfejs API sieci Web ASP.NET, aby zawsze zwracał JSON?
źródło
AKTUALIZACJA
Właśnie zobaczyłem głosy przeciw. Zobacz odpowiedź od „Steve” poniżej, aby dowiedzieć się, jak to zrobić.
ORYGINALNY
Śledziłem
JsonConvert.SerializeObject(key)
wywołanie metody przez odbicie (gdzie klucz był IList) i stwierdziłem, że JsonSerializerInternalWriter.SerializeList jest wywoływana. Pobiera listę i przechodzi przezfor (int i = 0; i < values.Count; i++) { ...
gdzie wartości to wprowadzony parametr IList.
Krótka odpowiedź brzmi ... Nie, nie ma wbudowanego sposobu ustawiania kolejności, w jakiej pola są wyświetlane w ciągu JSON.
źródło
Nie ma kolejności pól w formacie JSON, więc definiowanie kolejności nie ma sensu.
{ id: 1, name: 'John' }
jest równoważne{ name: 'John', id: 1 }
(oba reprezentują ściśle równoważną instancję obiektu)źródło