XmlSerializer
在序列化时实际上可以在枚举数据内部进行流式传输。它对于实现 IEnumerable<T>
接口的类有特殊处理。根据文档所述:
XmlSerializer 对实现 IEnumerable 或 ICollection 的类进行特殊处理。实现 IEnumerable 接口的类必须实现一个公共的 Add 方法,该方法需要一个参数。Add 方法的参数类型必须与从 GetEnumerator 返回的值的 Current 属性返回的类型相同,或者是该类型的基类之一。
在序列化这样的类时,XmlSerializer
只需遍历枚举并将每个当前值写入输出流中。 它不会先将整个可枚举对象加载到列表中。 因此,如果您有一些 Linq 查询,可以从数据库以块的形式动态分页返回类型为 T
的结果(例如这里),则可以使用以下包装器将它们全部序列化而无需一次性加载它们所有:
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(当然,我只是为测试目的将其写入字符串,而您可能会将其写入文件)。
IEnumerable<T>
吗?我认为你有这个能力。 - dbc