Saya mencoba untuk memperluas contoh JSON.net yang diberikan di sini http://james.newtonking.com/projects/json/help/CustomCreationConverter.html
Saya memiliki sub kelas lain yang berasal dari kelas dasar / Antarmuka
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Employee : Person
{
public string Department { get; set; }
public string JobTitle { get; set; }
}
public class Artist : Person
{
public string Skill { get; set; }
}
List<Person> people = new List<Person>
{
new Employee(),
new Employee(),
new Artist(),
};
Bagaimana saya membatalkan pendaftaran mengikuti Json kembali ke Daftar <Person>
[
{
"Department": "Department1",
"JobTitle": "JobTitle1",
"FirstName": "FirstName1",
"LastName": "LastName1"
},
{
"Department": "Department2",
"JobTitle": "JobTitle2",
"FirstName": "FirstName2",
"LastName": "LastName2"
},
{
"Skill": "Painter",
"FirstName": "FirstName3",
"LastName": "LastName3"
}
]
Saya tidak ingin menggunakan TypeNameHandling JsonSerializerSettings. Saya secara khusus mencari implementasi JsonConverter kustom untuk menangani ini. Dokumentasi dan contoh-contoh di sekitar ini sangat jarang di internet. Saya sepertinya tidak bisa mendapatkan implementasi metode ReadJson () yang ditimpa di JsonConverter benar.
c#
json
json.net
deserialization
Snakebyte
sumber
sumber
Jawaban:
Menggunakan standar
CustomCreationConverter
, saya berjuang untuk bekerja bagaimana menghasilkan tipe yang benar (Person
atauEmployee
), karena untuk menentukan ini Anda perlu menganalisis JSON dan tidak ada cara untuk melakukannya menggunakanCreate
metode ini.Saya menemukan utas diskusi yang berkaitan dengan konversi jenis dan ternyata memberikan jawabannya. Berikut ini tautannya: Ketik konversi .
Apa yang diperlukan adalah subclass
JsonConverter
, menggantiReadJson
metode dan membuatCreate
metode abstrak baru yang menerima aJObject
.ReadJson
Metode yang diganti membuatJObject
dan memanggilCreate
metode (diimplementasikan oleh kelas konverter kami yang diturunkan), lewat dalamJObject
instance.Mesin
JObject
virtual ini kemudian dapat dianalisis untuk menentukan jenis yang benar dengan memeriksa keberadaan bidang tertentu.Contoh
sumber
JsonReader
dibuat dalamReadJson
metode tidak mewarisi apapun nilai konfigurasi pembaca asli (Culture
,DateParseHandling
,DateTimeZoneHandling
,FloatParseHandling
, dll ...). Nilai-nilai ini harus disalin sebelum menggunakan baruJsonReader
diserializer.Populate()
.JsonConverter
memiliki properti yang dipanggilCanRead
danCanWrite
. Jika Anda tidak memerlukanWriteJson
implementasi kustom , cukup biarkanCanWrite
kembaliFALSE
. Sistem kemudian akan kembali ke perilaku default. @ jdavies: Silakan tambahkan itu ke jawaban Anda. Kalau tidak, itu akan crash pada serialisasi.Solusi di atas untuk
JsonCreationConverter<T>
semua ada di internet, tetapi memiliki kelemahan yang memanifestasikan dirinya dalam kesempatan langka. JsonReader baru yang dibuat dalam metode ReadJson tidak mewarisi nilai konfigurasi pembaca asli mana pun (Budaya, DateParseHandling, DateTimeZoneHandling, FloatParseHandling, dll ...). Nilai-nilai ini harus disalin sebelum menggunakan JsonReader baru di serializer.Populate ().Ini adalah yang terbaik yang bisa saya lakukan untuk memperbaiki beberapa masalah dengan implementasi di atas, tetapi saya masih berpikir ada beberapa hal yang diabaikan:
Pembaruan Saya memperbarui ini untuk memiliki metode yang lebih eksplisit yang membuat salinan pembaca yang ada. Ini hanya merangkum proses menyalin melalui pengaturan JsonReader individu. Idealnya fungsi ini akan dipertahankan di perpustakaan Newtonsoft itu sendiri, tetapi untuk saat ini, Anda dapat menggunakan yang berikut:
Ini harus digunakan sebagai berikut:
Solusi lama berikut:
sumber
Hanya berpikir saya akan berbagi solusi juga berdasarkan ini yang bekerja dengan atribut knowntype menggunakan refleksi, harus mendapatkan kelas turunan dari setiap kelas dasar, solusi dapat mengambil manfaat dari rekursi untuk menemukan kelas pencocokan terbaik meskipun saya tidak membutuhkannya di saya kasus, pencocokan dilakukan oleh jenis yang diberikan ke konverter jika memiliki Knowtypes itu akan memindai semuanya sampai cocok dengan jenis yang memiliki semua properti di dalam string json, yang pertama yang cocok akan dipilih.
penggunaannya sesederhana:
dalam kasus di atas ret akan dari tipe B.
Kelas JSON:
Kode konverter:
sumber
Proyek JsonSubTypes mengimplementasikan konverter generik yang menangani fitur ini dengan bantuan atribut.
Untuk sampel beton yang disediakan di sini adalah cara kerjanya:
sumber
Ini adalah perluasan jawaban totem. Itu pada dasarnya melakukan hal yang sama tetapi pencocokan properti didasarkan pada objek serial json, tidak mencerminkan objek .net. Ini penting jika Anda menggunakan [JsonProperty], menggunakan CamelCasePropertyNamesContractResolver, atau melakukan hal lain yang akan menyebabkan json tidak cocok dengan objek .net.
Penggunaannya sederhana:
Kode konverter:
sumber
Sebagai variasi lain pada solusi tipe Totem yang diketahui, Anda dapat menggunakan refleksi untuk membuat penyelesai tipe generik untuk menghindari keharusan menggunakan atribut tipe yang dikenal.
Ini menggunakan teknik yang mirip dengan GenericResolver Juval Lowy untuk WCF.
Selama kelas dasar Anda abstrak atau antarmuka, tipe yang dikenal akan ditentukan secara otomatis daripada harus didekorasi dengan atribut tipe yang dikenal.
Dalam kasus saya sendiri, saya memilih untuk menggunakan properti $ type untuk menunjuk tipe pada objek json saya daripada mencoba untuk menentukannya dari properti, meskipun Anda dapat meminjam dari solusi lain di sini untuk menggunakan penentuan berdasarkan properti.
Kemudian dapat diinstal sebagai formatter
sumber
Berikut solusi lain yang menghindari penggunaan
jObject.CreateReader()
, dan sebagai gantinya menciptakan yang baruJsonTextReader
(yang merupakan perilaku yang digunakan olehJsonCreate.Deserialze
metode default :sumber
Banyak kali implementasi akan ada di namespace yang sama dengan antarmuka. Jadi, saya datang dengan ini:
Karena itu, Anda dapat memasukkan ini secara global seperti:
sumber
Menggunakan ide totem dan zlangner , saya telah membuat sebuah
KnownTypeConverter
yang akan dapat menentukan pewaris yang paling tepat, sambil mempertimbangkan bahwa data json mungkin tidak memiliki elemen opsional.Jadi, layanan mengirimkan respons JSON yang berisi berbagai dokumen (masuk dan keluar). Dokumen memiliki kumpulan elemen yang sama dan elemen yang berbeda. Dalam hal ini, elemen yang terkait dengan dokumen keluar adalah opsional dan mungkin tidak ada.
Dalam hal ini, kelas dasar
Document
telah dibuat yang mencakup seperangkat properti yang umum. Dua kelas pewaris juga dibuat: -OutgoingDocument
menambahkan dua elemen opsional"device_id"
dan"msg_id"
; -IncomingDocument
menambahkan satu elemen wajib"sender_id"
;Tugasnya adalah membuat konverter yang didasarkan pada data json dan informasi dari FamousTypeAttribute akan dapat menentukan kelas yang paling tepat yang memungkinkan Anda menyimpan jumlah terbesar informasi yang diterima. Juga harus diperhitungkan bahwa data json mungkin tidak memiliki elemen opsional. Untuk mengurangi jumlah perbandingan elemen json dan properti model data, saya memutuskan untuk tidak mempertimbangkan sifat-sifat kelas dasar dan untuk berkorelasi dengan elemen json hanya sifat-sifat kelas warisan.
Data dari layanan:
Model data:
Konverter:
PS: Dalam kasus saya, jika tidak ada satu pewaris yang dipilih oleh konverter (ini dapat terjadi jika data JSON hanya berisi informasi dari kelas dasar atau data JSON tidak mengandung elemen opsional dari
OutgoingDocument
), maka objekOutgoingDocument
kelas tersebut akan dibuat, karena terdaftar pertama kali dalam daftarKnownTypeAttribute
atribut. Atas permintaan Anda, Anda dapat memvariasikan penerapanKnownTypeConverter
dalam situasi ini.sumber