XmlSerializer - произошла ошибка, отражающая тип

294

Используя С#.NET 2.0, у меня есть составной класс данных, у которого есть атрибут [Serializable]. Я создаю класс XMLSerializer и передаю его в конструктор:

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

Я получаю исключение:

Произошла ошибка, отражающая тип.

Внутри класса данных есть еще один составной объект. Должен ли это также иметь атрибут [Serializable] или его наличие на верхнем объекте, он рекурсивно применяет его ко всем объектам внутри?

Теги:
serialization
.net-2.0

16 ответов

392
Лучший ответ

Посмотрите на внутреннее исключение, которое вы получаете. Он расскажет вам, какое поле/свойство имеет проблемы с сериализацией.

Вы можете исключить поля/свойства из сериализации XML, украсив их атрибутом [XmlIgnore].

Я не думаю, что XmlSerializer использует атрибут [Serializable], поэтому я сомневаюсь, что это проблема.

  • 11
    У моего объекта было поле Uri, которое вызвало это исключение; класс Uri не имеет конструктора без параметров. Спасибо за чаевые.
  • 9
    Наткнулся на это с помощью поиска в Google - моя конкретная проблема заключалась в том, что в моем классе «быть сериализованным» было свойство « IList когда он должен был быть List .
Показать ещё 12 комментариев
104

Помните, что сериализованные классы должны иметь конструкторы по умолчанию (то есть без параметров). Если у вас нет никакого конструктора, это прекрасно; но если у вас есть конструктор с параметром, вам также нужно добавить значение по умолчанию.

  • 4
    Спасибо за напоминание! Я ненавижу, что это ошибка времени выполнения с небольшим объяснением.
  • 0
    Я продолжаю повторять эту ошибку снова и снова. спасибо, что напомнили мне использовать конструктор без параметров ^^
21

У меня была аналогичная проблема, и оказалось, что сериализатор не может отличить 2 класса, которые я имел с тем же именем (один из них был подклассом другого). Внутреннее исключение выглядело следующим образом:

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

Где BaseNamespace.SubNamespace.Class1 является подклассом BaseNamespace.Class1.

Мне нужно было добавить атрибут к одному из классов (я добавил в базовый класс):

[XmlType("BaseNamespace.Class1")]

Примечание. Если у вас больше слоев классов, вам также нужно добавить к ним атрибут.

  • 0
    Это исправило проблему для меня, спасибо, +1; У меня была похожая настройка с несколькими объектами Processor *, каждый с внутренним классом Config. Среда выполнения не смогла различить SomeNS.Processor1.Config и SomeNS.Processor2.Config.
6

Также имейте в виду, что XmlSerializer не может сериализовать абстрактные свойства. См. мой вопрос здесь (к которому я добавил код решения).

Сериализация XML и унаследованные типы

5

Все объекты в графе сериализации должны быть сериализованы.

Так как XMLSerializer является черным ящиком, проверьте эти ссылки, если вы хотите отлаживать дальше процесс сериализации.

Изменение, где XmlSerializer выводит временные сборки

КАК: Отлаживать сборку .NET XmlSerializer

4

Наиболее распространенные причины для меня:

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

Если вам нужно обрабатывать определенные атрибуты (например, словарь или любой класс), вы можете реализовать интерфейс 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

Я обнаружил, что класс Dictionary в .Net 2.0 не сериализуется с использованием XML, но сериализуется хорошо, когда используется двоичная сериализация.

Я нашел работу здесь.

3

Недавно я получил это в частичном классе веб-ссылки при добавлении нового свойства. Класс, созданный автоматически, добавлял следующие атрибуты.

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

Мне нужно было добавить аналогичный атрибут с порядком выше предыдущего в автоматически сгенерированной последовательности, и это исправило это для меня.

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

Я получил ту же ошибку и обнаружил, что проблема с типом IEnumerable<SomeClass> была проблемой. Похоже, что IEnumerable не может быть сериализовано напрямую.

0

У меня была такая же проблема, и в моем случае у объекта был ReadOnlyCollection. Коллекция должна реализовать метод Add для сериализации.

  • 0
    Это не правильный ответ на вопрос. На этот вопрос уже есть 15 других ответов. Если вы думаете, что ваш ответ лучше, чем другие, вы должны предоставить более подробную информацию о нем. Предоставление некоторого фрагмента кода и вывода всегда помогает пользователям. Прежде чем опубликовать свои ответы, подумайте о прочтении -> stackoverflow.com/help/how-to-answer
0

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

//Или

[XmlIgnore] string [] strFielsName {get; set;}

0

Я использую класс NetDataSerialiser для сериализации мои классы домена. класс NetDataContractSerializer.

Классы домена совместно используются клиентом и сервером.

0

Также обратите внимание, что вы не можете сериализовать элементы управления пользовательским интерфейсом и что любой объект, который вы хотите передать в буфер обмена, должен быть сериализуемым, иначе он не может быть передан другим процессам.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню