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 に絞り込みました。属性 [XmlIgnore] を設定すると、リストが xml 出力に含まれないため、逆シリアル化の速度が非常に速くなります。

ObservableCollection を使用してセットアップを改善し、このシナリオをより効率的に処理したいと考えていますが、オンラインで解決策を見つけることができません。

編集: 次の属性を試しました:

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

Xml が読みやすくなりますが、逆シリアル化の速度は向上しません。

4

1 に答える 1

2

デシリアライズ速度は、監視可能なコレクションが発生するイベントが原因である可能性があります。

このような状況で私が行うことは、問題のあるプロパティをXMLIgnoreとしてマークしてから、シリアル化可能であるが、List<>などのより単純なタイプの疑似プロパティを追加することです。新しいプロパティのゲッターとセッターで、データをシリアル化できないプロパティに出し入れします。

編集:

最初の提案には現在の逆シリアル化と同じパフォーマンスペナルティがあることに気付いたので、概念を修正して、発生するイベントを抑制しながら、監視可能なコレクションに一連のレコードを追加できるようにしました。

まず、ObservableCollectionから継承する特別なクラスを作成する必要があります。

public class FooCollection : ObservableCollection<Foo>
{
}

このクラス内に、レコードの範囲を追加できるメソッドを追加する必要があります。この場合はList <>形式で、レコードの追加中に通知が発生しないことを示します。

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

最後に、FooCollectionのシリアル化を抑制し、シリアル化可能なList <>プロパティを追加するために、GraphViewModel内の実装を少し変更する必要があります。

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

}
于 2013-01-02T19:42:01.177 に答える