XmlSerializer - Ada jenis kesalahan pemantulan

332

Menggunakan C # .NET 2.0, saya memiliki kelas data komposit yang memang memiliki [Serializable]atribut di atasnya. Saya membuat XMLSerializerkelas dan meneruskannya ke konstruktor:

XmlSerializer serializer = new XmlSerializer(typeof(DataClass));

Saya mendapat pengecualian yang mengatakan:

Ada kesalahan yang mencerminkan jenis.

Di dalam kelas data ada objek komposit lain. Apakah ini juga perlu memiliki [Serializable]atribut, atau dengan memilikinya pada objek teratas, apakah itu menerapkannya secara rekursif ke semua objek di dalam?

leora
sumber

Jawaban:

413

Lihatlah pengecualian batin yang Anda dapatkan. Ini akan memberi tahu Anda bidang / properti mana yang mengalami masalah serialisasi.

Anda dapat mengecualikan bidang / properti dari serialisasi xml dengan mendekorasi mereka dengan [XmlIgnore]atribut.

XmlSerializertidak menggunakan [Serializable]atribut, jadi saya ragu itu masalahnya.

Lamar
sumber
11
Objek saya memiliki bidang Uri, yang menyebabkan pengecualian ini; kelas Uri tidak memiliki konstruktor tanpa parameter. Terima kasih atas tipnya.
ford
10
Datangi ini dengan pencarian google - masalah khusus saya adalah memiliki properti di kelas "menjadi serial" seperti IListketika perlu List.
Paul Aldred-Bann
7
Bagaimana orang melihat "pengecualian batiniah"?
David
7
atau tambahkan 'pengecualian' ke arloji
arolson101
19
Terima kasih, jawaban ini membantu saya. Saya awalnya melihat pengecualian dalam, dan hanya melihat menyebutkan kelas utama. Tetapi saya menyadari bahwa saya dapat menelusuri ke dalam innerexceptions dari innrexceptions, dan akhirnya, 5 level ke bawah, saya menemukan masalah. Saya memiliki kelas yang saling bertentangan. Terima kasih.
Louis van Tonder
111

Ingat bahwa kelas serial harus memiliki konstruktor default (yaitu parameterless). Jika Anda tidak memiliki konstruktor sama sekali, itu bagus; tetapi jika Anda memiliki konstruktor dengan parameter, Anda harus menambahkan yang default juga.

Jeremy McGee
sumber
4
Terima kasih atas pengingatnya! Saya benci bahwa ini adalah kesalahan runtime dengan sedikit penjelasan.
Jared Updike
Saya terus membuat kesalahan ini berulang kali. terima kasih telah mengingatkan saya untuk menggunakan konstruktor tanpa parameter ^^
aZtraL-EnForceR
25

Saya memiliki masalah yang sama, dan ternyata serializer tidak dapat membedakan antara 2 kelas yang saya miliki dengan nama yang sama (satu adalah subkelas dari yang lain). Pengecualian batin terlihat seperti ini:

'Type BaseNamespace.Class1' dan 'BaseNamespace.SubNamespace.Class1' keduanya menggunakan nama tipe XML, 'Class1', dari namespace ''. Gunakan atribut XML untuk menentukan nama XML unik dan / atau namespace untuk jenisnya.

Di mana BaseNamespace.SubNamespace.Class1 adalah subclass dari BaseNamespace.Class1.

Apa yang perlu saya lakukan adalah menambahkan atribut ke salah satu kelas (saya menambahkan ke kelas dasar):

[XmlType("BaseNamespace.Class1")]

Catatan: Jika Anda memiliki lebih banyak lapisan kelas, Anda perlu menambahkan atribut ke mereka juga.

Dennis Calla
sumber
Ini memperbaiki masalah bagi saya, terima kasih, +1; Saya memiliki pengaturan yang mirip dengan beberapa objek Prosesor *, masing-masing dengan kelas batin Config. Runtime tidak dapat membedakan antara SomeNS.Processor1.Config dan SomeNS.Processor2.Config.
damix911
7

Perlu diketahui juga bahwa XmlSerializertidak dapat membuat serial properti abstrak .. Lihat pertanyaan saya di sini (yang telah saya tambahkan kode solusinya) ..

Serialisasi dan Jenis Warisan XML

Rob Cooper
sumber
6

Alasan paling umum menurut saya:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members
Stefan Michev
sumber
5

Jika Anda perlu menangani atribut tertentu (mis. Kamus, atau kelas apa pun), Anda dapat mengimplementasikan antarmuka IXmlSerialiable , yang akan memberi Anda lebih banyak kebebasan dengan biaya lebih banyak coding verbose .

public class NetService : IXmlSerializable
{
    #region Data

        public string Identifier = String.Empty;

        public string Name = String.Empty;

        public IPAddress Address = IPAddress.None;
        public int Port = 7777;

    #endregion

    #region IXmlSerializable Implementation

        public XmlSchema GetSchema() { return (null); }

        public void ReadXml(XmlReader reader)
        {
            // Attributes
            Identifier = reader[XML_IDENTIFIER];
            if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
            if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
        }

        public void WriteXml(XmlWriter writer)
        {
            // Attributes
            writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
            writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
            writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
        }

        private const string XML_IDENTIFIER = "Id";

        private const string XML_NETWORK_ADDR = "Address";

        private const string XML_NETWORK_PORT = "Port";

    #endregion
}

Ada artikel yang menarik , yang menunjukkan cara elegan untuk mengimplementasikan cara canggih untuk "memperluas" XmlSerializer.


Artikel itu mengatakan:

IXmlSerializable tercakup dalam dokumentasi resmi, tetapi dokumentasi menyatakan itu tidak dimaksudkan untuk penggunaan umum dan tidak memberikan informasi lebih dari itu. Ini menunjukkan bahwa tim pengembangan ingin memiliki hak untuk memodifikasi, menonaktifkan, atau bahkan menghapus sepenuhnya kemungkinan perpanjangan ini di jalan. Namun, selama Anda bersedia menerima ketidakpastian ini dan menghadapi kemungkinan perubahan di masa depan, tidak ada alasan apa pun yang tidak dapat Anda manfaatkan darinya.

Karena ini, saya sarankan untuk mengimplementasikan IXmlSerializablekelas Anda sendiri , untuk menghindari implementasi yang terlalu rumit.

... bisa langsung menerapkan XmlSerializerkelas kebiasaan kami menggunakan refleksi.

Luca
sumber
4

Saya telah menemukan bahwa kelas Kamus di .Net 2.0 tidak bisa serial menggunakan XML, tetapi membuat serialisasi dengan baik ketika serialisasi biner digunakan.

Saya menemukan pekerjaan di sekitar sini .

Charlie Garts
sumber
3

Baru-baru ini saya mendapatkannya di kelas parsial referensi web saat menambahkan properti baru. Kelas yang dibuat secara otomatis menambahkan atribut berikut.

    [System.Xml.Serialization.XmlElementAttribute(Order = XX)]

Saya perlu menambahkan atribut serupa dengan urutan yang lebih tinggi dari yang terakhir dalam urutan yang dibuat secara otomatis dan ini memperbaikinya untuk saya.

LepardUK
sumber
3

Saya baru saja mendapatkan kesalahan yang sama dan menemukan bahwa properti tipe IEnumerable<SomeClass>adalah masalahnya. Tampaknya IEnumerabletidak dapat diserialisasi secara langsung.

Sebaliknya, orang bisa menggunakan List<SomeClass>.

jkokorian
sumber
2

Saya juga berpikir bahwa atribut Serializable harus ada di objek tetapi kecuali jika saya menjadi noob lengkap (saya di tengah sesi pengkodean tengah malam) karya-karya berikut dari SnippetCompiler :

using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;

public class Inner
{
    private string _AnotherStringProperty;
    public string AnotherStringProperty 
    { 
      get { return _AnotherStringProperty; } 
      set { _AnotherStringProperty = value; } 
    }
}

public class DataClass
{
    private string _StringProperty;
    public string StringProperty 
    { 
       get { return _StringProperty; } 
       set{ _StringProperty = value; } 
    }

    private Inner _InnerObject;
    public Inner InnerObject 
    { 
       get { return _InnerObject; } 
       set { _InnerObject = value; } 
    }
}

public class MyClass
{

    public static void Main()
    {
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
            TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
            DataClass clazz = new DataClass();
            Inner inner = new Inner();
            inner.AnotherStringProperty = "Foo2";
            clazz.InnerObject = inner;
            clazz.StringProperty = "foo";
            serializer.Serialize(writer, clazz);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

}

Saya akan membayangkan bahwa XmlSerializer menggunakan refleksi atas properti publik.

Darren
sumber
1

Saya memiliki situasi di mana Ordo itu sama untuk dua elemen berturut-turut

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]

.... beberapa kode ...

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]

Ketika saya mengubah kode untuk menambah urutan dengan satu untuk setiap Properti baru di kelas, kesalahan hilang.

Jeremy Brown
sumber
1

Saya mendapatkan kesalahan yang sama ketika saya membuat properti yang memiliki tipe data - Type. Tentang ini, saya mendapatkan kesalahan - Ada jenis kesalahan yang mencerminkan. Saya terus memeriksa 'InnerException' dari setiap pengecualian dari dock debug dan mendapatkan nama bidang spesifik (yang Type) dalam kasus saya. Solusinya adalah sebagai berikut:

    [XmlIgnore]
    public Type Type { get; set; }
Iqra.
sumber
0

Juga perhatikan bahwa Anda tidak dapat membuat serial kontrol antarmuka pengguna dan bahwa objek apa pun yang ingin Anda lewati ke clipboard harus dapat serial jika tidak dapat dilewatkan ke proses lain.

Phil Wright
sumber
0

Saya telah menggunakan NetDataSerialiserkelas untuk membuat serialkan kelas domain saya. Kelas NetDataContractSerializer .

Kelas domain dibagi antara klien dan server.

Peter Mortensen
sumber
0

Saya memiliki masalah yang sama dan dalam kasus saya objek memiliki ReadOnlyCollection. Koleksi harus menerapkan metode Tambahkan agar dapat serial.

Penasaran Dev
sumber
Ini bukan jawaban yang tepat untuk pertanyaan itu. Sudah ada 15 jawaban lain untuk pertanyaan ini. Jika menurut Anda jawaban Anda lebih baik daripada yang lain, Anda harus memberikan perincian lebih lanjut tentang itu. Memberikan beberapa cuplikan kode & keluaran selalu membantu pengguna. Sebelum memposting jawaban Anda, pertimbangkan untuk membaca -> stackoverflow.com/help/how-to-answer
Amit Phaltankar
0

Saya memiliki solusi yang sedikit berbeda untuk semua yang dijelaskan di sini sejauh ini, jadi untuk setiap peradaban masa depan di sini milik saya!

Saya telah mendeklarasikan tipe data "waktu" karena tipe aslinya adalah a TimeSpandan kemudian diubah menjadi String:

[System.Xml.Serialization.XmlElementAttribute(DataType="time", Order=3)]

Namun tipe yang sebenarnya adalah string

public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

dengan menghapus DateTypeproperti tersebut Xmldapat diserialisasi

[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}
chxzy
sumber
0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

Atau

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
sumber