关于c#:XmlSerializer – 有一个反映类型的错误

XmlSerializer - There was an error reflecting type

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

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

我有个例外说:

There was an error reflecting type.

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


看看你得到的内在例外。它将告诉您它在序列化时遇到问题的字段/属性。

通过使用[XmlIgnore]属性对字段/属性进行修饰,可以从XML序列化中排除这些字段/属性。

我不认为XmlSerializer使用[Serializable]属性,所以我怀疑这是问题所在。


请记住,序列化类必须具有默认(即无参数)构造函数。如果您根本没有构造函数,那就可以了;但是如果您有一个带有参数的构造函数,那么您也需要添加默认的构造函数。


我也遇到了类似的问题,结果发现序列化程序无法区分我拥有的两个同名类(一个是另一个的子类)。内部异常如下所示:

"types basenamespace.class1"和"basenamespace.subnamespace.class1"都使用命名空间""中的XML类型名称"class1"。使用XML属性为类型指定唯一的XML名称和/或命名空间。

其中basenamespace.subnamespace.class1是basenamespace.class1的子类。

我需要做的是为其中一个类添加一个属性(我添加到基类中):

1
[XmlType("BaseNamespace.Class1")]

注意:如果您有更多的类层,您还需要向它们添加一个属性。


还要注意,XmlSerializer不能序列化抽象属性。请参阅我的问题(我已将解决方案代码添加到其中)。

XML序列化和继承的类型


我最常见的原因是:

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

如果您需要处理特定的属性(如字典或任何类),您可以实现IXMLSerialiable接口,这将允许您以更详细的编码为代价获得更多的自由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
}

有一篇有趣的文章,展示了一种实现"扩展"XML序列化程序的复杂方法的优雅方法。

文章说:

IXmlSerializable is covered in the official documentation, but the documentation states it's not intended for public use and provides no information beyond that. This indicates that the development team wanted to reserve the right to modify, disable, or even completely remove this extensibility hook down the road. However, as long as you're willing to accept this uncertainty and deal with possible changes in the future, there's no reason whatsoever you can't take advantage of it.

因为这样,我建议您实现自己的IXmlSerializable类,以避免实现太复杂。

…使用反射实现自定义XmlSerializer类可能很简单。


序列化图中的所有对象都必须是可序列化的。

由于XmlSerializer是一个黑盒,如果您想进一步调试到序列化过程中,请检查这些链接。

更改XmlSerializer输出临时程序集的位置

如何:调试到.NET XmlSerializer生成的程序集中


我发现.NET 2.0中的Dictionary类不能使用XML进行序列化,但在使用二进制序列化时可以很好地进行序列化。

我在这附近找到了一份工作。


我最近在添加新属性时在Web引用分部类中得到了这个。自动生成的类正在添加以下属性。

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

我需要添加一个类似的属性,它的顺序比自动生成序列中的最后一个高,这为我修复了它。


我也犯了同样的错误,发现问题出在IEnumerable类型的属性上。似乎IEnumerable不能直接序列化。

相反,我们可以使用List


我也认为序列化属性必须在对象上,但除非我是一个完整的noob(我正在进行一个深夜编码会话),否则代码片段编译器将执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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")]

…一些代码…

1
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName ="AccidentFlag")]

当我更改代码以使类中每个新属性的顺序增加一个时,错误就消失了。


我有同样的问题,在我的例子中,对象有一个readOnlyCollection。集合必须实现Add方法才能序列化。


[system.xml.serialization.xmleElementAttribute("strFieldName",form=system.xml.schema.xmlschemaForm.unqualified)]

//或

[XML忽略]字符串[]strfielsname get;set;


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


我一直在用NetDataSerialiser类来序列化我的域类。NetDataContractSerializer类。

域类在客户端和服务器之间共享。