XmlSerializer - 反映类型时发生了错误

369

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

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

我得到了一个异常,上面写着:

反射类型时发生错误。

在数据类中有另一个复合对象。 这个对象也需要有 [Serializable] 属性吗?还是只在顶层对象上有它就会递归地应用于内部所有对象?

19个回答

445

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

您可以使用[XmlIgnore]属性对字段/属性进行排除,以避免它们被xml序列化。

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


12
我的对象有一个Uri字段,这导致了异常;Uri类没有无参构造函数。谢谢提示。 - ford
11
我在谷歌搜索中发现了这个问题-我的特定问题是,我的“待序列化”类中有一个属性为IList,但它需要是List - Paul Aldred-Bann
7
如何查看“内部异常”? - David
7
或者将 '@exception' 添加到监视器中 - arolson101
29
谢谢,这个答案帮了我很多。起初我只看了内部异常,并且只看到提到了主类。但是我意识到我可以深入到内部异常的内部异常中,最终,向下五层,我找到了问题所在。我的类发生了冲突。谢谢。 - Louis van Tonder
显示剩余10条评论

119

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


4
谢谢提醒!我很讨厌这是一个运行时错误,却没有太多解释。 - Jared Updike
我一遍又一遍地犯这个错误。谢谢你提醒我使用无参构造函数^^ - aZtraL-EnForceR
如果序列化的“class”是委托,会怎样? - Steven Cool

29

我曾遇到一个类似的问题,原来是序列化器无法区分我两个同名的类(其中一个是另一个的子类)。内部异常看起来像这样:

'Types 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

8

我最常见的原因:

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

7

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类。

5

5
我刚遇到了同样的错误,并发现类型为 IEnumerable<SomeClass> 的一个属性是问题所在。看起来无法直接序列化 IEnumerable

相反,可以使用 List<SomeClass>


4
我发现在 .Net 2.0 中,Dictionary 类不能使用 XML 进行序列化,但是当使用二进制序列化时可以序列化成功。我在这里发现了一个解决方法(链接)

3

当我添加一个新属性时,我的 Web 引用局部类最近出现了这种情况。自动生成的类会添加以下属性。

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

我需要添加一个类似的属性,其顺序比自动生成的序列中最后一个高一个,并且这个方法对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接