まず、より良いタイトルを思い付くことができず申し訳ありません。でもやってみました。
私はこのようなクラスを持っています
public class GameBoard : ICloneable {
private bool _isCloned;
public ObservableCollection<BoardPosition> BoardPositions { get; set; }
public GameBoard() {
BoardPositions = new ObservableCollection<BoardPosition>();
//this.BoardPositions.CollectionChanged += BoardPositionsOnCollectionChanged;
}
private void BoardPositionsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) {
// if this event is raised from the NEW object, [this] still points to the OLD object
}
public object Clone() {
//var gameBoard = (GameBoard)this.MemberwiseClone();
var gameBoard = new GameBoard {
// make it VERY clear this is just a clone
_isCloned = true,
// deep copy the list of BoardPositions
BoardPositions =
new ObservableCollection<BoardPosition>(this.BoardPositions.Select(p => p.Clone()).Cast<BoardPosition>())
};
gameBoard.BoardPositions.CollectionChanged += BoardPositionsOnCollectionChanged;
// why does the target of the event point to the old object?!?
return gameBoard;
}
}
public class BoardPosition : ICloneable {
public int[] Coordinates { get; set; }
public BoardPosition(int[] coordinates) {
Coordinates = coordinates;
}
public object Clone() {
return new BoardPosition(new int[]{this.Coordinates[0], this.Coordinates[1], this.Coordinates[2]});
}
}
ICloneableを実装します。Cloneメソッド内で、ObservableCollectionをディープコピーし、CollectionChangedイベントハンドラーをアタッチします。
ここで問題となるのは、複製された新しいオブジェクトのCollectionChangedイベントが発生したときに、[this]が複製されたOLDオブジェクトを指していることです。クローン作成中にtrueに設定されていても、イベントが発生すると_isCLonedは常にfalseになるため、これは簡単に確認できます。これはなぜですか、そして私はそれについて何ができますか?もちろん、[this]に新しいクローンオブジェクトへの参照を持たせたいです。
var gameBoard = new GameBoard();
gameBoard.BoardPositions.Add(new BoardPosition(new[] {1, 2, 3}));
var clonedBoard = (GameBoard)gameBoard.Clone();
clonedBoard.BoardPositions.Add(new BoardPosition(new[] { 2, 3, 4 }));