使用XmlSerializer反序列化List<int>导致额外的项目

12

我注意到XmlSerializer和泛型列表(特别是List<int>)之间有一种奇怪的行为。我想知道是否有人以前遇到过这种情况或者知道这是怎么回事。看起来序列化工作正常,但反序列化却想要向列表中添加额外的项。下面的代码演示了这个问题。

可序列化的类:

public class ListTest
{
    public int[] Array { get; set; }
    public List<int> List { get; set; }

    public ListTest()
    {
        Array = new[] {1, 2, 3, 4};
        List = new List<int>(Array);
    }
}

测试代码:

ListTest listTest = new ListTest();
Debug.WriteLine("Initial Array: {0}", (object)String.Join(", ", listTest.Array));
Debug.WriteLine("Initial List: {0}", (object)String.Join(", ", listTest.List));

XmlSerializer serializer = new XmlSerializer(typeof(ListTest));
StringBuilder xml = new StringBuilder();
using(TextWriter writer = new StringWriter(xml))
{
    serializer.Serialize(writer, listTest);
}

Debug.WriteLine("XML: {0}", (object)xml.ToString());

using(TextReader reader = new StringReader(xml.ToString()))
{
    listTest = (ListTest) serializer.Deserialize(reader);
}

Debug.WriteLine("Deserialized Array: {0}", (object)String.Join(", ", listTest.Array));
Debug.WriteLine("Deserialized List: {0}", (object)String.Join(", ", listTest.List));

调试输出:

Initial Array: 1, 2, 3, 4
Initial List: 1, 2, 3, 4

XML:

<?xml version="1.0" encoding="utf-16"?>
<ListTest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Array>
    <int>1</int>
    <int>2</int>
    <int>3</int>
    <int>4</int>
  </Array>
  <List>
    <int>1</int>
    <int>2</int>
    <int>3</int>
    <int>4</int>
  </List>
</ListTest>
Deserialized Array: 1, 2, 3, 4
Deserialized List: 1, 2, 3, 4, 1, 2, 3, 4

请注意,数组和列表似乎都已经正确序列化为XML,但在反序列化时,数组得到了正确的结果,但列表却返回了一组重复的项。有什么想法吗?


1
感谢您的回答 - 正如我在下面的评论中提到的那样,我没有意识到反序列化程序能够在反序列化期间改变成员的状态(在大多数情况下,它只是设置新值,对吧?)。 List<T> 是唯一可以这样做的类吗? 有没有一些参考资料指出反序列化程序可以改变哪些类的状态? - daveaglick
2个回答

8
这种情况发生是因为你在构造函数中初始化了List。当你进行反序列化时,会创建一个新的ListTest对象,然后从状态中填充该对象。
可以将工作流程看作如下:
1. 创建一个新的ListTest对象 2. 执行构造函数(添加1、2、3、4) 3. 反序列化xml状态,并将1、2、3、4添加到列表中
一个简单的解决方法是在构造函数之外初始化对象。
public class ListTest
{
    public int[] Array { get; set; }
    public List<int> List { get; set; }

    public ListTest()
    {

    }

    public void Init() 
    {
        Array = new[] { 1, 2, 3, 4 };
        List = new List<int>(Array);
    }
}

ListTest listTest = new ListTest();
listTest.Init(); //manually call this to do the initial seed

4
问题在于您在默认构造函数中定义了List中的原始1,2,3,4。您的反序列化程序将添加到列表中,而不是定义它。

4
谢谢,将初始化代码移出构造函数确实解决了问题。我误解了反序列化的工作方式。我没有意识到它会改变现有对象,我以为它总是使用设置访问器来写入全新的子对象实例到新构造的对象中(在这种情况下,在构造函数中创建的列表就会被遗忘)。每天都有新的学习。 - daveaglick

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