在构造目标对象之前是否XmlSerializer.Deserialize
将整个文档加载到内存中?
XML 的内容来自我不完全信任的客户端。因此,我使用 XmlReader 以仅向前、不可回溯的方式对其进行解析。虽然XmlSerializer.Deserialize
可以从 XmlReader 反序列化,但我不确定它是否将从 XmlReader 读取的整个文档缓存到内存中,从而对系统造成内存压力。这将是不可取的。
我查看了MSDN,但似乎没有提及。我错过了什么吗?
在构造目标对象之前是否XmlSerializer.Deserialize
将整个文档加载到内存中?
XML 的内容来自我不完全信任的客户端。因此,我使用 XmlReader 以仅向前、不可回溯的方式对其进行解析。虽然XmlSerializer.Deserialize
可以从 XmlReader 反序列化,但我不确定它是否将从 XmlReader 读取的整个文档缓存到内存中,从而对系统造成内存压力。这将是不可取的。
我查看了MSDN,但似乎没有提及。我错过了什么吗?
简短的回答:不,它没有。
我带着完全相同的问题来到这里,很惊讶没有答案。首先,我曾考虑过测试,但后来我决定更深入地了解它。
所以我花了相当长的时间研究序列化/反序列化是如何工作的,探索了 .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
fromXmlReader
当然看起来像:
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
方法是以这种方式实现的,但对我来说更深入地了解事物的工作原理对我来说很有趣。