XmlSerializer - เกิดข้อผิดพลาดในการสะท้อนประเภท


332

เมื่อใช้ C # .NET 2.0 ฉันมีคลาสข้อมูลคอมโพสิตที่มี[Serializable]แอตทริบิวต์อยู่ ฉันกำลังสร้างXMLSerializerชั้นเรียนและส่งผ่านไปยังผู้สร้าง:

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

ฉันได้รับการยกเว้นว่า:

มีข้อผิดพลาดในการสะท้อนประเภท

ภายในคลาสข้อมูลมีวัตถุประกอบอื่นอยู่ สิ่งนี้จำเป็นต้องมีแอ[Serializable]ททริบิวต์หรือวางไว้ที่วัตถุด้านบนหรือไม่และนำไปใช้กับวัตถุทั้งหมดที่อยู่ข้างในซ้ำหรือไม่

คำตอบ:


413

ดูข้อยกเว้นภายในที่คุณได้รับ มันจะบอกคุณว่าเขตข้อมูล / ทรัพย์สินมันมีปัญหาในการเป็นอันดับ

คุณสามารถแยกฟิลด์ / คุณสมบัติออกจากการทำให้เป็นอนุกรม xml ได้โดยตกแต่งด้วยแอ[XmlIgnore]ททริบิวต์

XmlSerializerไม่ได้ใช้[Serializable]คุณลักษณะดังนั้นฉันสงสัยว่าเป็นปัญหา


11
วัตถุของฉันมีฟิลด์ Uri ซึ่งทำให้เกิดข้อยกเว้นนี้ คลาส Uri ไม่มีตัวสร้างแบบไม่มีพารามิเตอร์ ขอบคุณสำหรับทิป.
ฟอร์ด

10
มาข้ามนี้กับการค้นหาของ Google - โดยเฉพาะอย่างยิ่งปัญหาของฉันก็มีคุณสมบัติในของฉัน "ที่จะต่อเนื่อง" ชั้นเป็นเมื่อมันจำเป็นจะต้องIList List
Paul Aldred-Bann

7
เราจะดู "ข้อยกเว้นภายใน" ได้อย่างไร
เดวิด

7
หรือเพิ่ม '@exception' ในนาฬิกา
arolson101

19
ขอบคุณคำตอบนี้ช่วยฉันออก ตอนแรกฉันดูที่ข้อยกเว้นภายในและเพิ่งเห็นการกล่าวถึงชั้นเรียนหลัก แต่ฉันก็รู้ว่าฉันสามารถเจาะลึกถึงความต่างของความแปรปรวนร่วมและในที่สุดเมื่อลดลง 5 ระดับฉันก็พบปัญหา ฉันมีชั้นเรียนที่ขัดแย้งกัน ขอบคุณ
Louis van Tonder

111

จำไว้ว่าคลาสที่ต่อเนื่องกันต้องมีคอนสตรัคเตอร์เริ่มต้น (เช่นแบบไม่มีพารามิเตอร์) หากคุณไม่มีคอนสตรัคเตอร์เลยก็ไม่เป็นไร แต่ถ้าคุณมีคอนสตรัคเตอร์พร้อมพารามิเตอร์คุณจะต้องเพิ่มค่าเริ่มต้นด้วย


4
ขอบคุณสำหรับการเตือน! ฉันเกลียดที่นี่เป็นข้อผิดพลาด runtime พร้อมคำอธิบายเล็กน้อย
Jared Updike

ฉันทำผิดพลาดไปเรื่อย ๆ ขอบคุณที่เตือนให้ฉันใช้ตัวสร้างแบบไม่มีพารามิเตอร์ ^^
aZtraL-EnForceR

25

ฉันมีปัญหาที่คล้ายกันและปรากฎว่า serializer ไม่สามารถแยกความแตกต่างระหว่าง 2 คลาสที่ฉันมีชื่อเดียวกัน (หนึ่งคือ subclass ของอื่น ๆ ) ข้อยกเว้นภายในมีลักษณะเช่นนี้:

'Types BaseNamespace.Class1' และ 'BaseNamespace.SubNamespace.Class1' ทั้งสองใช้ชื่อประเภท XML, 'Class1' จาก namespace '' ใช้แอตทริบิวต์ XML เพื่อระบุชื่อ XML ที่ไม่ซ้ำกันและ / หรือเนมสเปซสำหรับประเภท

โดยที่ BaseNamespace.SubNamespace.Class1 เป็นคลาสย่อยของ BaseNamespace.Class1

สิ่งที่ฉันต้องทำคือเพิ่มแอตทริบิวต์ให้กับหนึ่งในคลาส (ฉันเพิ่มลงในคลาสฐาน):

[XmlType("BaseNamespace.Class1")]

หมายเหตุ: หากคุณมีชั้นเรียนเพิ่มขึ้นคุณจะต้องเพิ่มแอตทริบิวต์ให้กับชั้นเรียนด้วย


นี่เป็นการแก้ไขปัญหาสำหรับฉันขอบคุณ +1; ฉันมีการตั้งค่าที่คล้ายกันกับวัตถุตัวประมวลผล * หลายตัวซึ่งแต่ละตัวมีคลาสภายในตั้งค่า รันไทม์ไม่สามารถแยกความแตกต่างระหว่าง SomeNS.Processor1.Config และ SomeNS.Processor2.Config
damix911

7

โปรดระวังด้วยว่าXmlSerializerไม่สามารถทำให้เป็นนามธรรมคุณสมบัตินามธรรมดูคำถามของฉันที่นี่ (ซึ่งฉันได้เพิ่มรหัสวิธีการไป) ..

การทำให้เป็นอันดับ XML และประเภทที่สืบทอด


6

สาเหตุที่พบบ่อยที่สุดโดยฉัน:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members

5

วัตถุทั้งหมดในกราฟการทำให้เป็นอนุกรมจะต้องต่อเนื่องกันได้

เนื่องจากXMLSerializerเป็น blackbox ให้ตรวจสอบลิงก์เหล่านี้หากคุณต้องการแก้ปัญหาเพิ่มเติมในกระบวนการทำให้เป็นอนุกรม

การเปลี่ยนตำแหน่งที่ XmlSerializer ส่งออกชุดประกอบชั่วคราว

วิธีการ: ตรวจแก้จุดบกพร่องลงในแอสเซมบลีที่สร้าง. NET XmlSerializer


5

หากคุณจำเป็นต้องจับคุณลักษณะเฉพาะ (เช่นพจนานุกรมหรือระดับใด ๆ ) คุณสามารถใช้IXmlSerialiableอินเตอร์เฟซซึ่งจะช่วยให้คุณมีอิสระมากขึ้นค่าใช้จ่ายมากขึ้น 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
}

มีบทความที่น่าสนใจซึ่งแสดงวิธีการที่สวยงามในการใช้วิธีการที่ซับซ้อนเพื่อ "ขยาย" XmlSerializer


บทความพูดว่า:

IXmlSerializable ครอบคลุมในเอกสารอย่างเป็นทางการ แต่เอกสารระบุว่ามันไม่ได้มีไว้สำหรับการใช้งานสาธารณะและให้ข้อมูลไม่เกิน สิ่งนี้บ่งชี้ว่าทีมพัฒนาต้องการสงวนสิทธิ์ในการแก้ไขปิดการใช้งานหรือแม้กระทั่งลบส่วนขยายออกได้อย่างสมบูรณ์ อย่างไรก็ตามตราบใดที่คุณยินดียอมรับความไม่แน่นอนนี้และจัดการกับการเปลี่ยนแปลงที่อาจเกิดขึ้นในอนาคตก็ไม่มีเหตุผลใด ๆ ก็ตามที่คุณไม่สามารถใช้ประโยชน์จากมันได้

ด้วยเหตุนี้ฉันขอแนะนำให้คุณใช้IXmlSerializableคลาสของตัวเองเพื่อหลีกเลี่ยงการใช้งานที่ซับซ้อนมากเกินไป

... อาจเป็นเรื่องง่ายที่จะนำXmlSerializerคลาสที่เรากำหนดเองมาใช้โดยใช้การสะท้อน


4

ฉันได้ค้นพบว่าคลาส Dictionary ใน. Net 2.0 นั้นไม่สามารถต่ออนุกรมได้โดยใช้ XML แต่เป็นอนุกรมที่ดีเมื่อใช้ซีเรียลไลซ์เซชั่นแบบไบนารี

ฉันพบว่าการทำงานรอบที่นี่


3

ฉันเพิ่งได้รับสิ่งนี้ในการอ้างอิงทางเว็บบางส่วนเมื่อเพิ่มคุณสมบัติใหม่ คลาสที่สร้างโดยอัตโนมัติเพิ่มคุณสมบัติดังต่อไปนี้

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

ฉันต้องการเพิ่มแอตทริบิวต์ที่คล้ายกันโดยมีคำสั่งซื้อสูงกว่าลำดับสุดท้ายในลำดับที่สร้างโดยอัตโนมัติและสิ่งนี้จะแก้ไขให้ฉัน


3

ฉันเพิ่งได้รับข้อผิดพลาดเดียวกันและพบว่าคุณสมบัติประเภทIEnumerable<SomeClass>เป็นปัญหา ปรากฏว่าIEnumerableไม่สามารถต่อเนื่องได้โดยตรง

แต่สามารถใช้งานList<SomeClass>ได้


2

ฉันก็คิดว่าแอตทริบิวต์ Serializable ต้องอยู่ในวัตถุ แต่ถ้าฉันเป็น noob ที่สมบูรณ์ (ฉันอยู่ในช่วงกลางของการเข้ารหัสช่วงดึก) งานต่อไปนี้จาก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();
        }
    }

}

ฉันคิดว่า XmlSerializer ใช้การสะท้อนมากกว่าคุณสมบัติสาธารณะ


1

ฉันมีสถานการณ์ที่สั่งซื้อเหมือนกันสำหรับสององค์ประกอบในแถว

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

.... บางรหัส ...

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

เมื่อฉันเปลี่ยนรหัสเพื่อเพิ่มลำดับโดยหนึ่งสำหรับคุณสมบัติใหม่แต่ละรายการในคลาสข้อผิดพลาดก็หายไป


1

ผมได้รับข้อผิดพลาดเดียวกันเมื่อฉันสร้างสถานที่ให้บริการที่มีประเภทข้อมูลที่ Type- เกี่ยวกับเรื่องนี้ฉันได้รับข้อผิดพลาด - มีข้อผิดพลาดในการสะท้อนประเภท ฉันตรวจสอบ 'InnerException' ทุกข้อยกเว้นจาก debug dock และได้รับชื่อฟิลด์เฉพาะ (ซึ่งก็คือType) ในกรณีของฉัน วิธีแก้ปัญหามีดังนี้:

    [XmlIgnore]
    public Type Type { get; set; }

0

นอกจากนี้โปรดทราบว่าคุณไม่สามารถซีเรียลอินเทอร์เฟซผู้ใช้เป็นตัวควบคุมและวัตถุใด ๆ ที่คุณต้องการส่งผ่านไปยังคลิปบอร์ดจะต้องสามารถทำให้เป็นอนุกรมได้มิฉะนั้นจะไม่สามารถส่งผ่านไปยังกระบวนการอื่นได้



0

ฉันมีปัญหาเดียวกันและในกรณีของฉันวัตถุมี ReadOnlyCollection คอลเลกชันจะต้องใช้วิธีการเพิ่มเพื่อให้เป็นอนุกรม


นี่ไม่ใช่คำตอบที่ถูกต้องสำหรับคำถาม มี 15 คำตอบสำหรับคำถามนี้แล้ว หากคุณคิดว่าคำตอบของคุณดีกว่าคำตอบอื่น ๆ คุณควรให้รายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้ การให้ข้อมูลโค้ดและผลลัพธ์บางอย่างจะช่วยผู้ใช้เสมอ ก่อนโพสต์คำตอบของคุณให้อ่าน -> stackoverflow.com/help/how-to-answer
Amit Phaltankar

0

ฉันมีทางออกที่แตกต่างกันเล็กน้อยสำหรับการอธิบายทั้งหมดที่นี่จนถึงปัจจุบันสำหรับอารยธรรมในอนาคตที่นี่เป็นของฉัน

ฉันได้ประกาศประเภทข้อมูลของ "เวลา" ตามประเภทเดิมTimeSpanแล้วและเปลี่ยนเป็นString:

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

อย่างไรก็ตามชนิดที่แท้จริงคือสตริง

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

โดยการลบDateTypeคุณสมบัติที่Xmlสามารถต่อเนื่องกันได้

[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

หรือ

[XmlIgnore]
string [] strFielsName {get;set;}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.