2013-01-02 76 views
1
[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的反序列化非常缓慢

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

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

编辑: 我曾尝试以下属性:

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

它使XML的可读性更好,但不会提高速度反序列化。

回答

2

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

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

编辑:

我意识到,最初建议将具有相同的性能损失作为当前反序列化呢,所以我已经修改了这个概念,允许添加范围的记录,以观察集合,同时抑制了事件否则会被提出。

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

public class FooCollection : ObservableCollection<Foo> 
{ 
} 

该类别中,我们需要添加一个方法,让我们添加了一系列的记录,在这种情况下列表<>形式,并指出,我们不希望发生,而我们所添加的记录通知:

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的系列化,并添加一个序列化的列表<>属性:

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); 
     } 
    } 

} 
+0

我现在推行的概念。 – faldeland

+1

@faldeland:我已经用更好的方法更新了答案,应该可以大大提高性能。 –

+0

我期待明天实施这个... – faldeland