我喜欢XmlSerialize如何工作,如此简单和优雅,并且使用attributes = p但是,在序列化为xml文件之前,我在构建所有对象的集合时遇到了Out of Memory问题。
我正在从SQL数据库填充对象,并打算使用XmlSerialize将对象写入XML。它适用于小型子集,但如果我尝试从数据库中获取所有对象,则会出现Out of Memory异常。
是否有一些XmlSerialize的能力允许我从数据库中抓取100批对象,然后编写它们,抓取下一批100个对象并附加到xml?
我希望我不必破坏XmlDocument或需要更多手动编码工作的东西......
答案 0 :(得分:4)
XmlSerializer
可以在序列化时流入和流出可枚举的数据。它对实现IEnumerable<T>
的类有特殊处理。来自docs:
XmlSerializer为实现IEnumerable或ICollection的类提供特殊处理。实现IEnumerable的类必须实现一个带有单个参数的公共Add方法。 Add方法的参数必须与从GetEnumerator返回的值的Current属性返回的类型相同,或者是该类型的基础之一。
在序列化这些类时,XmlSerializer
只是遍历可枚举的每个当前值写入输出流。它不会首先将整个枚举加载到列表中。因此,如果您有一些Linq查询从块中的数据库(例如here)中动态分页类型T
的结果,那么您可以将所有这些查询序列化,而无需使用以下方法一次性加载所有这些查询包装器:
// Proxy class for any enumerable with the requisite `Add` methods.
public class EnumerableProxy<T> : IEnumerable<T>
{
[XmlIgnore]
public IEnumerable<T> BaseEnumerable { get; set; }
public void Add(T obj)
{
throw new NotImplementedException();
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
if (BaseEnumerable == null)
return Enumerable.Empty<T>().GetEnumerator();
return BaseEnumerable.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
请注意,此类仅对序列化有用,而不是反序列化。以下是如何使用它的示例:
public class RootObject<T>
{
[XmlIgnore]
public IEnumerable<T> Results { get; set; }
[XmlArray("Results")]
public EnumerableProxy<T> ResultsProxy {
get
{
return new EnumerableProxy<T> { BaseEnumerable = Results };
}
set
{
throw new NotImplementedException();
}
}
}
public class TestClass
{
XmlWriter xmlWriter;
TextWriter textWriter;
public void Test()
{
try
{
var root = new RootObject<int>();
root.Results = GetResults();
using (textWriter = new StringWriter())
{
var settings = new XmlWriterSettings { Indent = true, IndentChars = " " };
using (xmlWriter = XmlWriter.Create(textWriter, settings))
{
(new XmlSerializer(root.GetType())).Serialize(xmlWriter, root);
}
var xml = textWriter.ToString();
Debug.WriteLine(xml);
}
}
finally
{
xmlWriter = null;
textWriter = null;
}
}
IEnumerable<int> GetResults()
{
foreach (var i in Enumerable.Range(0, 1000))
{
if (i > 0 && (i % 500) == 0)
{
HalfwayPoint();
}
yield return i;
}
}
private void HalfwayPoint()
{
if (xmlWriter != null)
{
xmlWriter.Flush();
var xml = textWriter.ToString();
Debug.WriteLine(xml);
}
}
}
如果在HalfwayPoint()
中设置中断,您将看到已经写出了一半的XML,同时仍在迭代可枚举的内容。 (当然,我只是写一个字符串用于测试目的,而你可能正在写一个文件。)