saya pikir dia mungkin tertarik untuk menunjukkan bidang ID (atau serupa) pertama, dan kemudian semua bidang lainnya. ini lebih ramah untuk pengguna akhir daripada mencarinya setelah bidang yang dimulai dengan A..I
Michael Bahig
3
Properti JSON didefinisikan sebagai tidak berurutan. Saya pikir itu benar-benar baik-baik saja untuk memaksakan perintah OUTPUT tertentu selama serialisasi (demi melihat JSON mungkin), tapi itu akan menjadi keputusan yang buruk untuk membuat DEPENDENSI pada urutan tertentu tentang deserialisasi.
DaBlick
5
Beberapa alasan yang valid: (1) memalsukan properti "$ type" yang harus menjadi properti pertama di JSON, (2) mencoba menghasilkan JSON yang mengompres sebanyak mungkin
Stephen Chung
4
Alasan lain mungkin (3) representasi kanonik yang menggunakan sintaks JSON - objek yang sama harus dijamin untuk menghasilkan string JSON yang sama. Urutan atribut yang deterministik merupakan prasyarat yang diperlukan untuk ini.
MarkusSchaber
2
Kevin, dapatkah Anda memperbarui jawaban yang diterima pada pertanyaan ini?
Millie Smith
Jawaban:
256
Cara yang didukung adalah dengan menggunakan JsonPropertyatribut pada properti kelas yang ingin Anda atur urutannya. Baca dokumentasi pesanan JsonPropertyAttribute untuk informasi lebih lanjut.
Lulus JsonPropertysebuah Ordernilai dan serializer akan mengurus sisanya.
[JsonProperty(Order=1)]
Ini sangat mirip dengan
DataMember(Order=1)
System.Runtime.Serializationhari - hari.
Ini adalah catatan penting dari @ kevin-babcock
... mengatur pesanan ke 1 hanya akan berfungsi jika Anda menetapkan pesanan lebih besar dari 1 pada semua properti lainnya. Secara default, properti apa pun tanpa pengaturan Pesanan akan diberi urutan -1. Jadi, Anda harus memberikan semua properti dan pesanan berseri, atau mengatur item pertama Anda ke -2
Menggunakan Orderproperti dari JsonPropertyAttributedapat digunakan untuk mengontrol urutan bidang yang serial / deserialized. Namun, mengatur pesanan ke 1 hanya akan berfungsi jika Anda menetapkan pesanan lebih besar dari 1 pada semua properti lainnya. Secara default, properti apa pun tanpa pengaturan Pesanan akan diberi urutan -1. Jadi, Anda harus memberikan semua properti dan pesanan berseri, atau mengatur item pertama Anda ke -2.
Kevin Babcock
1
Ini berfungsi untuk serialisasi, tetapi urutannya tidak dipertimbangkan pada deserialisasi. Menurut dokumentasi, atribut urutan digunakan untuk serialisasi dan deserialisasi. Apakah ada solusinya?
cangosta
1
Apakah ada properti serupa untuk JavaScriptSerializer.
Shimmy Weitzhandler
4
@cangosta Urutan untuk deserialisasi seharusnya tidak penting .. kecuali dalam beberapa kasus harapan yang sangat "aneh".
user2864740
1
Baca diskusi masalah github serupa di sekitar keinginan agar Orde dihormati dalam deserialisasi: github.com/JamesNK/Newtonsoft.Json/issues/758 Pada dasarnya tidak ada kesempatan untuk ini.
Tyeth
126
Anda benar-benar dapat mengontrol urutan dengan menerapkan IContractResolveratau override DefaultContractResolver's CreatePropertiesmetode.
Berikut adalah contoh implementasi sederhana saya IContractResolveryang memesan properti secara alfabet:
Ini cukup membantu (+1) tetapi satu peringatan: tampaknya serialisasi kamus tidak menggunakan kustomisasi CreateProperties ini. Mereka membuat serial baik-baik saja tetapi tidak berakhir diurutkan. Saya berasumsi ada cara berbeda untuk menyesuaikan serialisasi kamus, tetapi saya belum menemukannya.
solublefish
Sempurna. Melakukan apa yang saya inginkan. Terima kasih.
Wade Hatler
Ini solusi hebat. Bekerja dengan sempurna untuk saya terutama ketika meletakkan 2 objek JSON berdampingan dan memiliki properti yang sejajar.
Vince
16
Dalam kasus saya, jawaban Mattias tidak berhasil. The CreatePropertiesMetode tidak pernah disebut.
Setelah debugging Newtonsoft.Jsoninternal, saya datang dengan solusi lain.
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;}}
Ini adalah perbaikan yang diperlukan bagi kami saat menggunakan dikt.
noocyte
Ini menambah biaya tambahan deserialisasi dan serialisasi tambahan. Saya telah menambahkan solusi yang akan bekerja untuk kelas normal, kamus dan ExpandoObject (objek dinamis) juga
Jay Shah
11
Dalam kasus saya, solusi niaher tidak berfungsi karena tidak menangani objek dalam array.
Ini menambah biaya tambahan deserialisasi dan serialisasi tambahan.
Jay Shah
Solusi yang sangat baik. Terima kasih.
MaYaN
3
Seperti yang dicatat Charlie, Anda dapat mengontrol urutan properti JSON dengan memesan properti di kelas itu sendiri. Sayangnya, pendekatan ini tidak berfungsi untuk properti yang diwarisi dari kelas dasar. Properti kelas dasar akan dipesan karena mereka diletakkan dalam kode, tetapi akan muncul sebelum properti kelas dasar.
Dan bagi siapa pun yang bertanya-tanya mengapa Anda mungkin ingin mengabjadkan properti JSON, jauh lebih mudah untuk bekerja dengan file JSON mentah, terutama untuk kelas dengan banyak properti, jika dipesan.
Bukankah ini perilaku pemesanan default selama serialisasi?
mr5
1
Untuk menghemat waktu beberapa menit, perhatikan bahwa jawaban ini tidak berfungsi untuk kamus meskipun ada klaim. CreatePropertiestidak dipanggil selama serialisasi kamus. Saya menjelajahi repo JSON.net untuk mesin apa yang sebenarnya menembus entri kamus. Itu tidak terhubung ke overridekustomisasi apa pun atau lainnya untuk memesan. Itu hanya mengambil entri apa adanya dari pencacah objek. Sepertinya saya harus membuat SortedDictionaryatau SortedListmemaksa JSON.net untuk melakukan ini. Saran fitur diajukan: github.com/JamesNK/Newtonsoft.Json/issues/2270
William
2
Jika Anda tidak ingin menempatkan JsonPropertyOrderatribut pada setiap properti kelas, maka sangat mudah untuk membuat ContractResolver Anda sendiri ...
Antarmuka IContractResolver menyediakan cara untuk menyesuaikan bagaimana JsonSerializer membuat serial dan deserializes .NET objek ke JSON tanpa menempatkan atribut pada kelas Anda.
Seperti ini:
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;}}
Melaksanakan:
var settings =newJsonSerializerSettings{ContractResolver=SortedPropertiesContractResolver.Instance};var json =JsonConvert.SerializeObject(obj,Formatting.Indented, settings);
Metode rekursif berikut menggunakan refleksi untuk mengurutkan daftar token internal pada JObjectinstance yang ada daripada membuat grafik objek yang diurutkan baru. Kode ini bergantung pada detail implementasi Json.NET internal dan tidak boleh digunakan dalam produksi.
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);}}
Jika Anda mengontrol (yaitu menulis) kelas, letakkan properti dalam urutan abjad dan mereka akan berseri dalam urutan abjad ketika JsonConvert.SerializeObject()dipanggil.
Saya ingin membuat serial objek comblex dan menjaga urutan properti seperti yang didefinisikan dalam kode. Saya tidak bisa menambahkan [JsonProperty(Order = 1)]karena kelas itu sendiri berada di luar jangkauan saya.
Solusi ini juga memperhitungkan bahwa properti yang didefinisikan dalam kelas dasar harus memiliki prioritas yang lebih tinggi.
Ini mungkin bukan antipeluru, karena tidak ada tempat yang MetaDataAttributememastikan bahwa urutan yang benar, tetapi tampaknya berfungsi. Untuk kasus penggunaan saya ini ok. karena saya hanya ingin mempertahankan keterbacaan manusia untuk file konfigurasi yang dihasilkan secara otomatis.
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();}}
Saya baru saja melihat downvotes. Silakan lihat jawaban dari 'Steve' di bawah untuk cara melakukan ini.
ASLI
Saya mengikuti JsonConvert.SerializeObject(key)pemanggilan metode melalui refleksi (di mana kuncinya adalah IList) dan menemukan bahwa JsonSerializerInternalWriter.SerializeList dipanggil. Dibutuhkan daftar dan loop melalui
for (int i = 0; i < values.Count; i++) { ...
di mana nilai adalah parameter IList yang dibawa.
Jawaban singkatnya adalah ... Tidak, tidak ada cara untuk mengatur urutan kolom yang tercantum dalam string JSON.
@Darin - tetapi ada perintah dalam serialisasi. "{id: 1, name: 'John'}" dan "{name: 'John', id: 1}" berbeda dengan string , yang merupakan perhatian saya di sini. Tentu saja, benda-benda itu setara ketika deserialized.
Kevin Montrose
1
@Darin - tidak, tidak dalam kasus ini. Saya membuat serial sesuatu dan kemudian meneruskannya sebagai string ke layanan yang hanya berurusan dengan string (bukan JSON sadari), dan akan lebih mudah untuk berbagai alasan untuk satu bidang muncul pertama kali dalam string.
Kevin Montrose
1
itu bagus untuk pengujian juga, bisa hanya melihat string daripada harus deserialize.
Steve
9
Urutan serialisasi yang stabil juga berguna untuk validasi cache. Ini sepele untuk mengambil checksum dari sebuah string - tidak berlaku untuk grafik objek penuh.
solublefish
1
Urutan serialisasi juga berguna saat melakukan tes unit sehingga Anda dapat dengan mudah mengatakan bahwa string respons yang diharapkan vs yang sebenarnya sama bahkan ketika urutan properti json berbeda.
Jawaban:
Cara yang didukung adalah dengan menggunakan
JsonProperty
atribut pada properti kelas yang ingin Anda atur urutannya. Baca dokumentasi pesanan JsonPropertyAttribute untuk informasi lebih lanjut.Lulus
JsonProperty
sebuahOrder
nilai dan serializer akan mengurus sisanya.Ini sangat mirip dengan
System.Runtime.Serialization
hari - hari.Ini adalah catatan penting dari @ kevin-babcock
sumber
Order
properti dariJsonPropertyAttribute
dapat digunakan untuk mengontrol urutan bidang yang serial / deserialized. Namun, mengatur pesanan ke 1 hanya akan berfungsi jika Anda menetapkan pesanan lebih besar dari 1 pada semua properti lainnya. Secara default, properti apa pun tanpa pengaturan Pesanan akan diberi urutan -1. Jadi, Anda harus memberikan semua properti dan pesanan berseri, atau mengatur item pertama Anda ke -2.JavaScriptSerializer
.Anda benar-benar dapat mengontrol urutan dengan menerapkan
IContractResolver
atau overrideDefaultContractResolver
'sCreateProperties
metode.Berikut adalah contoh implementasi sederhana saya
IContractResolver
yang memesan properti secara alfabet:Dan kemudian mengatur pengaturan dan membuat serial objek, dan bidang JSON akan berada dalam urutan abjad:
sumber
Dalam kasus saya, jawaban Mattias tidak berhasil. The
CreateProperties
Metode tidak pernah disebut.Setelah debugging
Newtonsoft.Json
internal, saya datang dengan solusi lain.sumber
Dalam kasus saya, solusi niaher tidak berfungsi karena tidak menangani objek dalam array.
Berdasarkan solusinya, inilah yang saya hasilkan
sumber
Seperti yang dicatat Charlie, Anda dapat mengontrol urutan properti JSON dengan memesan properti di kelas itu sendiri. Sayangnya, pendekatan ini tidak berfungsi untuk properti yang diwarisi dari kelas dasar. Properti kelas dasar akan dipesan karena mereka diletakkan dalam kode, tetapi akan muncul sebelum properti kelas dasar.
Dan bagi siapa pun yang bertanya-tanya mengapa Anda mungkin ingin mengabjadkan properti JSON, jauh lebih mudah untuk bekerja dengan file JSON mentah, terutama untuk kelas dengan banyak properti, jika dipesan.
sumber
Ini akan berfungsi untuk kelas normal, kamus dan ExpandoObject (objek dinamis) juga.
sumber
CreateProperties
tidak dipanggil selama serialisasi kamus. Saya menjelajahi repo JSON.net untuk mesin apa yang sebenarnya menembus entri kamus. Itu tidak terhubung keoverride
kustomisasi apa pun atau lainnya untuk memesan. Itu hanya mengambil entri apa adanya dari pencacah objek. Sepertinya saya harus membuatSortedDictionary
atauSortedList
memaksa JSON.net untuk melakukan ini. Saran fitur diajukan: github.com/JamesNK/Newtonsoft.Json/issues/2270Jika Anda tidak ingin menempatkan
JsonProperty
Order
atribut pada setiap properti kelas, maka sangat mudah untuk membuat ContractResolver Anda sendiri ...Seperti ini:
Melaksanakan:
sumber
Metode rekursif berikut menggunakan refleksi untuk mengurutkan daftar token internal pada
JObject
instance yang ada daripada membuat grafik objek yang diurutkan baru. Kode ini bergantung pada detail implementasi Json.NET internal dan tidak boleh digunakan dalam produksi.sumber
Sebenarnya, karena Object saya sudah menjadi JObject, saya menggunakan solusi berikut:
dan kemudian gunakan seperti ini:
sumber
Jika Anda mengontrol (yaitu menulis) kelas, letakkan properti dalam urutan abjad dan mereka akan berseri dalam urutan abjad ketika
JsonConvert.SerializeObject()
dipanggil.sumber
Saya ingin membuat serial objek comblex dan menjaga urutan properti seperti yang didefinisikan dalam kode. Saya tidak bisa menambahkan
[JsonProperty(Order = 1)]
karena kelas itu sendiri berada di luar jangkauan saya.Solusi ini juga memperhitungkan bahwa properti yang didefinisikan dalam kelas dasar harus memiliki prioritas yang lebih tinggi.
Ini mungkin bukan antipeluru, karena tidak ada tempat yang
MetaDataAttribute
memastikan bahwa urutan yang benar, tetapi tampaknya berfungsi. Untuk kasus penggunaan saya ini ok. karena saya hanya ingin mempertahankan keterbacaan manusia untuk file konfigurasi yang dihasilkan secara otomatis.sumber
Jika Anda ingin mengonfigurasi API Anda secara global dengan bidang yang dipesan, silakan gabungkan jawaban Mattias Nordberg:
dengan jawaban saya di sini:
Bagaimana cara memaksa ASP.NET Web API untuk selalu mengembalikan JSON?
sumber
MEMPERBARUI
Saya baru saja melihat downvotes. Silakan lihat jawaban dari 'Steve' di bawah untuk cara melakukan ini.
ASLI
Saya mengikuti
JsonConvert.SerializeObject(key)
pemanggilan metode melalui refleksi (di mana kuncinya adalah IList) dan menemukan bahwa JsonSerializerInternalWriter.SerializeList dipanggil. Dibutuhkan daftar dan loop melaluifor (int i = 0; i < values.Count; i++) { ...
di mana nilai adalah parameter IList yang dibawa.
Jawaban singkatnya adalah ... Tidak, tidak ada cara untuk mengatur urutan kolom yang tercantum dalam string JSON.
sumber
Tidak ada urutan bidang dalam format JSON sehingga mendefinisikan pesanan tidak masuk akal.
{ id: 1, name: 'John' }
setara dengan{ name: 'John', id: 1 }
(keduanya mewakili instance objek yang sangat setara)sumber