2

在构造目标对象之前是否XmlSerializer.Deserialize将整个文档加载到内存中?

XML 的内容来自我不完全信任的客户端。因此,我使用 XmlReader 以仅向前、不可回溯的方式对其进行解析。虽然XmlSerializer.Deserialize可以从 XmlReader 反序列化,但我不确定它是否将从 XmlReader 读取的整个文档缓存到内存中,从而对系统造成内存压力。这将是不可取的。

我查看了MSDN,但似乎没有提及。我错过了什么吗?

4

1 回答 1

1

简短的回答:不,它没有。

我带着完全相同的问题来到这里,很惊讶没有答案。首先,我曾考虑过测试,但后来我决定更深入地了解它。
所以我花了相当长的时间研究序列化/反序列化是如何工作的,探索了 .NET Framework 源代码和动态生成的程序集。
这是我的小调查中的关键代码部分(省略了无关紧要的部分)。

假设我们给出:

using (StreamReader reader = new StreamReader(filepath))
{
    var foobars = (List<Foobar>)serializer.Deserialize(reader);
}

之后,我们将进入这个XmlSerializer类方法:

public object Deserialize(TextReader textReader) 
{ 
    XmlTextReader xmlReader = new XmlTextReader(textReader);
    return Deserialize(xmlReader, null); 
}

这导致我们:

public object Deserialize(XmlReader xmlReader, string encodingStyle, XmlDeserializationEvents events)
{
    // instantiate specific for our class Reader 
    // from dynamically generated assembly
    XmlSerializationReader reader = CreateReader(); 
    reader.Init(xmlReader, events, encodingStyle, tempAssembly); 
    try { 
        //call dynamically generated for out particular type method
        return Deserialize(reader);
    } 
    finally {
        reader.Dispose();
    }
}

动态生成的代码如下所示:

public class XmlSerializationReaderList1 : XmlSerializationReader
{
    protected override object Deserialize(XmlSerializationReader reader)
    {
        return ((XmlSerializationReaderList1) reader).Read3_ArrayOfFoobar();
    }

    // this is the method which do all work, huge part of it is omitted
    public object Read3_ArrayOfFoobar()
    {
        // this.Reader is XmlSerializationReader field of type XmlReader
        this.Reader.ReadStartElement();
        int num2 = (int) this.Reader.MoveToContent();
        int whileIterations = 0;
        int readerCount = this.ReaderCount;
        while ((this.Reader.NodeType == XmlNodeType.EndElement ? 0 : (this.Reader.NodeType != XmlNodeType.None ? 1 : 0)) != 0)
        {
            if (this.Reader.NodeType == XmlNodeType.Element)
            {
            if ((this.Reader.LocalName != this.id3_Foobar ? 0 : (this.Reader.NamespaceURI == this.id2_Item ? 1 : 0)) != 0)
            {
                if (list == null)
                this.Reader.Skip();
                else
                list.Add(this.Read2_Foobar(true, true));
            }
            else
                this.UnknownNode((object) null, ":Foobar");
            }
            else
            this.UnknownNode((object) null, ":Foobar");
            int num3 = (int) this.Reader.MoveToContent();
            this.CheckReaderCount
    }

    private Foobar Read2_Foobar(bool isNullable, bool checkType) { //... }
}

MoveToContentfromXmlReader当然看起来像:

public virtual XmlNodeType MoveToContent()
{
  do
  {
    switch (this.NodeType)
    {
      case XmlNodeType.Element:
      case XmlNodeType.Text:
      case XmlNodeType.CDATA:
      case XmlNodeType.EntityReference:
      case XmlNodeType.EndElement:
      case XmlNodeType.EndEntity:
        return this.NodeType;
      case XmlNodeType.Attribute:
        this.MoveToElement();
        goto case XmlNodeType.Element;
      default:
        continue;
    }
  }
  while (this.Read());
  return this.NodeType;
}

当然,从一开始就很明显,Deserialize方法是以这种方式实现的,但对我来说更深入地了解事物的工作原理对我来说很有趣。

于 2013-11-10T20:29:56.797 回答