XmlSerializer.Deserialize是否在内存中加载整个文档?

时间:2013-10-13 20:41:01

标签: c# .net xml deserialization xmlserializer

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

XML的内容来自客户端,我并不完全信任。因此,我正在使用XmlReader以前向,非后退的方式解析它。虽然XmlSerializer.Deserialize可以从XmlReader反序列化,但我不确定它是否将从XmlReader读取的整个文档缓存到内存中,从而给系统带来内存压力。这将是不受欢迎的。

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

1 个答案:

答案 0 :(得分: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) { //... }
}
来自MoveToContent

XmlReader看起来像是:

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方法以这种方式实现,但对我来说,了解事情的运作方式对我来说很有意思。