通过XmlSerializer序列化类工作正常,但ObservableCollection的反序列化非常慢

时间:2013-01-02 19:34:59

标签: c# observablecollection xmlserializer

    [Serializable]
    public class GraphViewModel : ViewModelBase
    {    
        public GraphViewModel()
        {
            //Constructor
        }

        public bool bool1 { get; set; }
        public bool bool2 { get; set; }
        public bool bool3 { get; set; }
        public ObservableCollection<Foo> Foos { get; set; }
    }

使用上面的示例类,我可以序列化并插入到二进制数据库字段中没问题。当我反序列化时,一切正常,但速度很慢(3到25秒之间)。注意:列表中只有5个项目。

我已将问题缩小到ObservableCollection。当我设置属性[XmlIgnore]时,反序列化的速度非常好,因为列表不包含在xml输出中。

我更愿意使用ObservableCollection并改进我的设置以更有效地处理这种情况,但无法在线找到解决方案。

修改 我尝试了以下属性:

[XmlArray(ElementName = "Foos")]
[XmlArrayItem(ElementName = "Foo")]
public ObservableCollection<Foo> Foos { get; set; }

它使Xml更具可读性,但不会提高反序列化速度。

1 个答案:

答案 0 :(得分:2)

反序列化速度很可能是由于可观察集合引发的事件。

我在这种情况下所做的是将违规属性标记为XMLIgnore,然后添加一个可序列化的伪属性,但类型更简单,例如List&lt;&gt;。在新属性的getter和setter中,只需将数据移入和移出非序列化属性。

编辑:

我意识到最初的建议与当前的反序列化具有相同的性能损失,因此我修改了概念以允许向可观察集合添加一系列记录,同时抑制否则将引发的事件。

首先,我们需要创建一个继承自ObservableCollection的特殊类:

public class FooCollection : ObservableCollection<Foo>
{
}

在这个类中,我们需要添加一个允许我们添加一系列记录的方法,在本例中是List&lt;&gt;表格并表明我们在添加记录时不希望发生通知:

    private bool m_fSuppressNotifications;

    public void AddRange(List<Foo> cItems)
    {
        if ((cItems == null) || (cItems.Count == 0)) {
            this.Clear();
        } else {
            try
            {
                // Keep events from being fired
                m_fSuppressNotifications = true;
                foreach (var oFoo in cItems)
                {
                    this.Add(oFoo);
                }
            }
            finally
            {
                m_fSuppressNotifications = false;
                // Raise the event to notify any listeners that the data has changed
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
            }
        }
    }

最后,我们需要覆盖与CollectionChanged相关的元素,并禁止或手动执行相关事件:

    public override event NotifyCollectionChangedEventHandler CollectionChanged;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // Prevent infinite loop that could occur if handler changes the collection
        using (BlockReentrancy())
        {
            if (!m_fSuppressNotifications)
            {
                // Get the current event
                var oCollectionChangedEvent = this.CollectionChanged;
                if (oCollectionChangedEvent != null)
                {
                    foreach (EventHandler oHandler in oCollectionChangedEvent.GetInvocationList())
                    {
                        // Execute the handler
                        oHandler(this, e);
                    }
                }
            }
        }
    }

最后,我们需要稍微更改GraphViewModel中的实现,以便抑制FooCollection的序列化并添加可序列化的List&lt;&gt;属性:

public class GraphViewModel
{
    [XmlIgnore]
    public FooCollection Foos { get; set; }

    [XmlArray(ElementName = "Foos")]
    [XmlArrayItem(ElementName = "Foo")]
    public List<Foo> FoosSerializable
    {
        get
        {
            return this.Foos.ToList<Foo>();
        }
        set
        {
            this.Foos.AddRange(value);
        }
    }

}