XmlSerializer - произошла ошибка при отображении типа

332

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

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

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

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

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

Лиора
источник

Ответы:

413

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

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

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

Lamar
источник
11
У моего объекта было поле Uri, которое вызвало это исключение; класс Uri не имеет конструктора без параметров. Спасибо за чаевые.
Форд
10
Наткнулся на это с помощью поиска в Google - моя конкретная проблема заключалась в том, что в моем классе «для сериализации» было свойство, IListкогда это было необходимо List.
Пол Олдред-Банн
7
Как посмотреть на «внутреннее исключение»?
Дэвид
7
или добавьте '@exception' к часам
arolson101
19
Спасибо, этот ответ помог мне. Я сначала посмотрел на внутреннее исключение и только увидел упоминание основного класса. Но я понял, что могу углубиться в неисключения исключений, и в конце концов, на 5 уровней ниже, я обнаружил проблему. У меня были классы, которые были противоречивы. Спасибо.
Луи ван Тондер
111

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

Джереми МакГи
источник
4
Спасибо за напоминание! Я ненавижу, что это ошибка времени выполнения с небольшим объяснением.
Джаред Апдайк
Я продолжаю повторять эту ошибку снова и снова. спасибо, что напомнили мне использовать конструктор без параметров ^^
aZtraL-EnForceR
25

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

Типы 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

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

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

Чарли Солтс
источник
3

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

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

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

LepardUK
источник
3

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

Вместо этого можно использовать List<SomeClass>.

jkokorian
источник
2

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

Я использовал этот NetDataSerialiserкласс для сериализации классов моего домена. NetDataContractSerializer Class .

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

Питер Мортенсен
источник
0

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

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

У меня есть немного другое решение для всех описанных здесь до сих пор, так что для любой будущей цивилизации здесь мое!

Я объявил тип данных «время», так как исходный тип был 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");
    }
}
chxzy
источник
0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

Или

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
источник