XmlSerializer - виникла помилка типу відображення


332

Використовуючи C # .NET 2.0, у мене є складений клас даних, у якого є [Serializable]атрибут. Я створюю XMLSerializerклас і передаю його в конструктор:

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

Я отримую виняток, кажучи:

Виникла помилка типу відображення.

Всередині класу даних знаходиться ще один складений об’єкт. Чи має це також мати [Serializable]атрибут, чи він, застосовуючи його на верхньому об'єкті, рекурсивно застосовує його до всіх об'єктів всередині?

Відповіді:


413

Подивіться на внутрішній виняток, який ви отримуєте. Він підкаже вам, яке поле / властивість має проблеми з серіалізацією.

Ви можете виключити поля / властивості з xml серіалізації, прикрасивши їх [XmlIgnore]атрибутом.

XmlSerializerне використовує [Serializable]атрибут, тому я сумніваюся, що це проблема.


11
Мій об’єкт мав поле Урі, що спричинило цей виняток; клас Uri не має конструктора без параметрів. Дякую за пораду.
ford

10
Я зіткнувся з цим через пошук в Google - моя особлива проблема полягала в тому, що в моєму класі "бути серіалізованим" було властивість так, IListяк це було потрібно List.
Пол Олдред-Бан

7
Як можна дивитися на "внутрішній виняток"?
Девід

7
або додайте "@exception" на годинник
arolson101

19
Дякую, ця відповідь допомогла мені. Я спочатку подивився на внутрішній виняток і щойно побачив згадку про головний клас. Але я зрозумів, що можу розібратися в незрозумілих уявленнях, і, врешті-решт, на 5 рівнів нижче я знайшов проблему. У мене були заняття, які були суперечливими. Дякую.
Луї ван Тондер

111

Пам'ятайте, що серіалізовані класи повинні мати конструктори за замовчуванням (тобто без параметрів). Якщо у вас взагалі немає конструктора, це добре; але якщо у вас є конструктор з параметром, вам також потрібно буде додати типовий.


4
Дякуємо за нагадування! Я ненавиджу, що це помилка виконання з невеликим поясненням.
Jared Updike

Я продовжую робити цю помилку знову і знову. дякую за те, що нагадали мені використовувати конструктор без параметрів ^^
aZtraL-EnForceR

25

У мене була подібна проблема, і виявилося, що серіалізатор не міг розрізнити два класи, які я мав з однаковою назвою (один був підкласом іншого). Внутрішній виняток виглядав так:

"Типи BaseNamespace.Class1" і "BaseNamespace.SubNamespace.Class1" обидва використовують назву типу XML "Class1" з простору імен "'. Використовуйте атрибути XML, щоб вказати унікальне ім'я XML та / або простір імен для типу.

Де BaseNamespace.SubNamespace.Class1 - це підклас BaseNamespace.Class1.

Що мені потрібно було зробити - це додати атрибут до одного з класів (я додав до базового класу):

[XmlType("BaseNamespace.Class1")]

Примітка. Якщо у вас є більше шарів класів, вам потрібно також додати атрибут.


Це вирішило для мене проблему, дякую, +1; У мене було подібне налаштування з декількома об’єктами Processor *, кожен з яких має внутрішній клас Config. Під час виконання не вдалося розрізнити SomeNS.Processor1.Config та SomeNS.Processor2.Config.
damix911


6

Найпоширеніші мої причини:

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

5

Усі об'єкти в графіку серіалізації повинні бути серіалізаційними.

Оскільки XMLSerializerце чорний ящик, перевірте ці посилання, якщо ви хочете далі налагоджувати процес серіалізації.

Зміна місця, де XmlSerializer виводить тимчасові збори

ЯК: Налагодження в збірці .NET XmlSerializer


5

Якщо вам потрібно обробити конкретні атрибути (наприклад, словник або будь-який клас), ви можете реалізувати інтерфейс IXmlSerialiable , який дозволить вам отримати більше свободи за рахунок більш детального кодування .

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

Я виявив, що клас словника в .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' кожного винятку з док-наладу для налагодження і отримав конкретне ім’я поля (яке було Type) у моєму випадку. Рішення полягає в наступному:

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

0

Також зауважте, що ви не можете серіалізувати елементи керування інтерфейсом користувача і що будь-який об’єкт, який ви хочете передати у буфер обміну, повинен бути серіалізаційним, інакше він не може бути переданий іншим процесам.



0

У мене була така ж проблема, і в моєму випадку об’єкт мав ReadOnlyCollection. Колекція повинна реалізувати метод Add, щоб бути серіалізаційним.


Це не правильна відповідь на питання. На це питання вже є 15 відповідей. Якщо ви вважаєте, що ваша відповідь краща за інші, вам слід надати більше деталей про неї. Надання деяких фрагментів коду та виводу завжди допомагає користувачам. Перш ніж розміщувати свої відповіді вважають читання -> stackoverflow.com/help/how-to-answer
Amit Phaltankar

0

У мене є дещо інше рішення для всіх описаних тут поки що, тому для будь-якої майбутньої цивілізації ось моя!

Я оголосив тип даних "time", оскільки початковий тип був a, 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;}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.