調査してたらこんな問題が…
前、StatefulModel を魔改造して使っているといってましたが、ロック回数とか減らすために AddRange
とかの複数オブジェクトを一度に追加するバージョンのメソッドを追加しているんです (ろくにテストはしてないんですけどね)
今までだとこう実装してたわけですよ。
public void AddRange(IEnumerable<T> items) { if (items == null) throw new ArgumentNullException(nameof(items)); if (items.Count() == 0) throw new ArgumentException(nameof(items)); ReadAndWriteWithLockAction( () => { foreach (var item in items) { this._list.Add(item); } }, () => { this.OnPropertyChanged("Count"); this.OnPropertyChanged("Item[]"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items.ToArray(), this._list.Count - itemsList.Length)); }); }
でまあ IE<T>
の忘れがちな落とし穴で遅延実行なわけじゃないですか。でまあ、foreach
と ToArray()
で二回動くんで、別々のオブジェクトができるんですよね。正しくは以下のように実装しました。
public void AddRange(IEnumerable<T> items) { if (items == null) throw new ArgumentNullException(nameof(items)); var count = items.Count(); if (count == 0) throw new ArgumentException(nameof(items)); // 予め配列にでも書きだしておく var ary = new T[count]; var idx = 0; foreach (var item in items) ary[idx++] = item; ReadAndWriteWithLockAction( () => { foreach (var item in ary) { this._list.Add(item); } }, () => { this.OnPropertyChanged("Count"); this.OnPropertyChanged("Item[]"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, ary.ToArray(), this._list.Count - itemsList.Length)); }); }
やらかしてしまった事象ですね。いかんです。