Saya menulis kode untuk melakukan serialisasi Xml. Dengan fungsi di bawah ini.
public static string SerializeToXml(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
Jika argumen adalah turunan dari kelas tanpa konstruktor tanpa parameter, ia akan melempar pengecualian.
Pengecualian Tidak Tertangani: System.InvalidOperationException: CSharpConsole.Foo tidak dapat diserialisasi karena tidak memiliki konstruktor tanpa parameter. di System.Xml.Serialization.TypeDesc.CheckSupported () di System.Xml.Serialization.TypeScope.GetTypeDesc (jenis Type, MemberInfo sumber Referensi langsung Boolean) di System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (tipe Type, XmlRootAttribute root, String defaultNamespace) di System.Xml.Serialization.XmlSerializer..ctor (tipe type, String defaultName space) di System.Xml.Serationization. XmlSerializer..ctor (Jenis tipe)
Mengapa harus ada konstruktor tanpa parameter untuk memungkinkan serialisasi xml berhasil?
EDIT: terima kasih atas jawaban cfeduke. Konstruktor tanpa parameter dapat bersifat pribadi atau internal.
sumber
XmlSerializer
membutuhkan konstruktor tanpa parameter default untuk deserialisasi.Jawaban:
Selama de-serialisasi objek, kelas yang bertanggung jawab untuk de-serialisasi objek menciptakan turunan dari kelas serial dan kemudian melanjutkan untuk mengisi bidang dan properti serial hanya setelah memperoleh sebuah instance untuk diisi.
Anda dapat membuat konstruktor
private
atauinternal
jika Anda mau, asalkan tanpa parameter.sumber
private
atauinternal
, semua properti Anda yang nilainya diserialisasi harus memilikipublic
setter.Ini adalah batasan
XmlSerializer
. Catat ituBinaryFormatter
danDataContractSerializer
jangan memerlukan ini - mereka dapat membuat objek yang tidak diinisialisasi dari eter dan menginisialisasi itu selama deserialisasi.Karena Anda menggunakan xml, Anda dapat mempertimbangkan menggunakan
DataContractSerializer
dan menandai kelas Anda dengan[DataContract]
/[DataMember
], tetapi perhatikan bahwa ini mengubah skema (misalnya, tidak ada yang setara dengan[XmlAttribute]
- semuanya menjadi elemen).Pembaruan: jika Anda benar-benar ingin tahu,
BinaryFormatter
dan lain-lain gunakanFormatterServices.GetUninitializedObject()
untuk membuat objek tanpa memanggil konstruktor. Mungkin berbahaya; Saya tidak menyarankan terlalu sering menggunakannya ;-p Lihat juga komentar di MSDN:Saya memiliki mesin serialisasi sendiri , tetapi saya tidak bermaksud menggunakannya
FormatterServices
; Saya sangat suka mengetahui bahwa seorang konstruktor ( konstruktor apa saja ) sebenarnya telah dieksekusi.sumber
FormatterServices
penggunaan untuk usiaIXmlSerializable
, tapi: itu terjadi setelah konstruktor, dan b: sangat jelek dan sulit untuk mendapatkan hak (terutama deserialization) - saya sangat menyarankan agar mencoba untuk menerapkan itu, tapi: tidak akan memungkinkan Anda untuk menggunakan konstruktorJawabannya adalah: tanpa alasan apa pun.
Bertentangan dengan namanya,
XmlSerializer
kelas ini digunakan tidak hanya untuk serialisasi, tetapi juga untuk deserialisasi. Ia melakukan pemeriksaan tertentu di kelas Anda untuk memastikan bahwa itu akan berfungsi, dan beberapa cek itu hanya berkaitan dengan deserialisasi, tetapi tetap melakukan semuanya, karena tidak tahu apa yang ingin Anda lakukan nanti.Cek yang gagal lulus oleh kelas Anda adalah salah satu cek yang hanya berkaitan dengan deserialisasi. Inilah yang terjadi:
Selama deserialisasi,
XmlSerializer
kelas perlu membuat instance tipe Anda.Untuk membuat turunan dari suatu tipe, konstruktor dari tipe itu perlu dipanggil.
Jika Anda tidak mendeklarasikan konstruktor, kompilator telah menyediakan konstruktor tanpa parameter default, tetapi jika Anda mendeklarasikan konstruktor, maka itulah satu-satunya konstruktor yang tersedia.
Jadi, jika konstruktor yang Anda deklarasikan menerima parameter, maka satu-satunya cara untuk membuat instance kelas Anda adalah dengan memanggil konstruktor yang menerima parameter.
Namun,
XmlSerializer
tidak mampu memanggil konstruktor apa pun kecuali konstruktor tanpa parameter, karena tidak tahu parameter apa yang dilewatkan ke konstruktor yang menerima parameter. Jadi, ini memeriksa untuk melihat apakah kelas Anda memiliki konstruktor tanpa parameter, dan karena tidak, itu gagal.Jadi, jika
XmlSerializer
kelas telah ditulis sedemikian rupa untuk hanya melakukan pemeriksaan yang berkaitan dengan serialisasi, maka kelas Anda akan lulus, karena sama sekali tidak ada tentang serialisasi yang membuatnya perlu untuk memiliki konstruktor tanpa parameter.Seperti yang telah ditunjukkan orang lain, solusi cepat untuk masalah Anda adalah dengan menambahkan konstruktor tanpa parameter. Sayangnya, ini juga merupakan solusi kotor, karena itu berarti Anda tidak dapat memiliki
readonly
anggota yang diinisialisasi dari parameter konstruktor.Selain semua ini,
XmlSerializer
kelas dapat ditulis sedemikian rupa untuk memungkinkan deserialisasi kelas tanpa konstruktor tanpa parameter. Yang diperlukan hanyalah memanfaatkan "Pola Desain Metode Pabrik" (Wikipedia) . Dari kelihatannya, Microsoft memutuskan bahwa pola desain ini terlalu maju untuk programmer DotNet, yang tampaknya tidak perlu bingung dengan hal-hal seperti itu. Jadi, programmer DotNet harus lebih baik tetap menggunakan konstruktor tanpa parameter, menurut Microsoft.sumber
For no good reason whatsoever,
lalu lanjutkan dengan mengatakan,XmlSerializer is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters.
Jika tidak tahu parameter apa yang harus dilewatkan ke konstruktor, lalu bagaimana ia tahu parameter apa yang dilewatkan ke pabrik? Atau pabrik mana yang digunakan? Saya tidak bisa membayangkan alat ini lebih mudah digunakan - Anda ingin kelas deserialized, lalu biarkan deserializer membuat contoh default dan kemudian mengisi setiap bidang yang Anda tandai. Mudah.Pertama-tama, inilah yang tertulis dalam dokumentasi . Saya pikir ini adalah salah satu bidang kelas Anda, bukan yang utama - dan bagaimana Anda ingin deserialiser membangunnya kembali tanpa konstruksi parameterless?
Saya pikir ada solusi untuk menjadikan konstruktor sebagai pribadi.
sumber