XmlSerializer-反映类型错误


332

使用C#.NET 2.0,我有一个复合数据类,它确实具有[Serializable]属性。我正在创建一个XMLSerializer类,并将其传递给构造函数:

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

我正在说一个例外:

反映类型时发生错误。

在数据类内部,还有另一个复合对象。这是否还需要具有该[Serializable]属性,或者通过将其放在顶部对象上,是否将其递归地应用于内部的所有对象?

Answers:


413

查看您所得到的内部异常。它将告诉您序列化哪个字段/属性。

您可以通过使用[XmlIgnore]属性装饰字段/属性来将它们从xml序列化中排除。

XmlSerializer不使用该[Serializable]属性,因此我怀疑这是问题所在。


11
我的对象有一个Uri字段,导致了此异常。Uri类没有无参数的构造函数。谢谢你的提示。
福特

10
谷歌搜索解决了这一问题-我的特殊问题是在我的“要序列化”类中有一个属性,该属性是IList必要的List
Paul Aldred-Bann

7
人们如何看待“内部例外”?
大卫

7
或在手表中添加“ @exception”
arolson101 2013年

19
谢谢,这个答案帮助了我。我最初查看的是内部异常,只是看到提到主类。但是我意识到我可以深入研究innrexceptions的innerexceptions,最终将其降低5个级别。我的课有冲突。谢谢。
路易·范·唐德

111

请记住,序列化的类必须具有默认(即无参数)构造函数。如果根本没有构造函数,那很好。但是如果您有一个带参数的构造函数,则还需要添加默认的构造函数。


4
感谢您的提醒!我讨厌这是一个运行时错误,几乎没有解释。
Jared Updike

我不断重复犯这个错误。感谢您提醒我使用无参数构造函数^^
aZtraL-EnForceR 2014年

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 2012年




5

如果需要处理特定的属性(即Dictionary或任何类),则可以实现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中的Dictionary类无法使用XML进行序列化,但是在使用二进制序列化时可以很好地进行序列化。

我发现周围的工作在这里


3

我最近在添加新属性时将其放在Web参考分部类中。自动生成的类正在添加以下属性。

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

我需要添加一个类似的属性,其顺序比自动生成的序列中的最后一个顺序高,这对我来说是固定的。


3

我只是遇到了同样的错误,发现类型的属性IEnumerable<SomeClass>是问题所在。似乎IEnumerable无法直接序列化。

相反,可以使用List<SomeClass>


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")]

当我更改代码以将类中每个新Property的顺序递增一时,错误消失了。


1

创建具有数据类型-的属性时遇到相同的错误Type。对此,我遇到了一个错误-反映类型的错误。我不断从调试坞中检查每个异常的“ InnerException”,并获得了特定的字段名称(Type在我的情况下为)。解决方法如下:

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

0

还要注意,您不能序列化用户界面控件,并且要传递到剪贴板的任何对象都必须可序列化,否则不能传递给其他进程。



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");
    }
}

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

要么

[XmlIgnore]
string [] strFielsName {get;set;}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.