您可以使用 protobuf-net 执行此操作,只需在接收系统中使用 ObservableCollection<Person>。当反序列化期间集合增长到大于 5000 个对象时,请在 ObservableCollection<T>.CollectionChanged 回调中删除并处理这些项目。然后在 [OnDeserialized] 回调中处理任何剩余的项目。
例如,考虑以下根对象:
[ProtoContract]
public class RootObject
{
public RootObject()
{
this.People = new ObservableCollection<Person>();
}
[ProtoMember(1)]
public ObservableCollection<Person> People { get; private set; }
public event EventHandler<EventArgs<StreamingContext>> OnDeserialized;
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
var onDeserialized = OnDeserialized;
if (onDeserialized != null)
onDeserialized(this, new EventArgs<StreamingContext> { Value = context });
}
}
public class EventArgs<T> : EventArgs
{
public T Value { get; set; }
}
假设您想调用一个方法来处理每个被添加到集合中的 5000 个Person 对象,例如:
const int ProcessIncrement = 5000;
void ProcessItems(ICollection<Person> people, bool force)
{
if (people == null || people.Count == 0)
return;
if (people.Count >= ProcessIncrement || force)
{
// Remove and process the items, possibly on a different thread.
Console.WriteLine(string.Format("Processing {0} people." people.Count));
people.Clear();
}
}
您可以预先分配您的RootObject 并添加具有必要逻辑的侦听器,并将序列化流的内容合并到根:
// Allocate a new RootObject
var newRoot = new RootObject();
// Add listeners to process chunks of Person objects as they are added
newRoot.People.CollectionChanged += (o, e) =>
{
// Process each chunk of 5000.
var collection = (ICollection<Person>)o;
ProcessItems(collection, false);
};
newRoot.OnDeserialized += (o, e) =>
{
// Forcibly process any remaining no matter how many.
ProcessItems(((RootObject)o).People, true);
};
// Deserialize from the stream onto the pre-allocated newRoot
Serializer.Merge(stream, newRoot);
根据需要,每次将对象添加到集合时都会调用ProcessItems,以 5000 为增量处理它们,然后无条件处理剩余部分。
现在,唯一的问题是,protobuf-net 是在反序列化集合之前将整个流加载到内存中,还是进行流反序列化?事实证明,它是后者,正如sample fiddle 所示,随着People 集合中的项目被添加、处理和删除,流位置逐渐增加。
这里我在反序列化之前手动将监听器添加到RootObject。如果您要将它们添加到构造函数本身,您可以在预分配的根对象上使用 ProtoBuf.Serializer.Deserialize<RootObject>(Stream stream) 而不是 Serializer.Merge,这可能更容易集成到您当前的架构中。
顺便说一下,这种技术也应该适用于 XmlSerializer 和 Json.NET。