0

まず、より良いタイトルを思い付くことができず申し訳ありません。でもやってみました。

私はこのようなクラスを持っています

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

3 に答える 3

4

これは、新しく作成されたオブジェクトのメソッドをアタッチするのではなく、BoardPositionsOnCollectionChanged複製されるオブジェクトにメソッドをアタッチするためです。

つまり、使用する参照を明示的に指定する必要があります。そうしないと、コンパイラはthis元のオブジェクトであるを想定します。

// your code ("this." is added implicitly):
gameBoard.BoardPositions.CollectionChanged += this.BoardPositionsOnCollectionChanged;

// working code:
gameBoard.BoardPositions.CollectionChanged += gameBoard.BoardPositionsOnCollectionChanged;
于 2013-02-28T08:02:12.390 に答える
0

イベントのターゲットが古いオブジェクトを指すのはなぜですか?

古いオブジェクトの Clone メソッド内でハンドラーを割り当てているためです。ここでは当て推量を行っています (ここには C# コンパイラはありません) が、過去に同様の問題が発生したことを覚えています。Clone では、"this" が古いオブジェクトです。BoardPositionsOnCollectionChanged は、その時点で現在の「this」参照に解決されるため、常に「古い」オブジェクトへの参照を処理します。

別の「Init」メソッドで代入を因数分解して、新しいインスタンスで呼び出すことができます。

void Init() {
   BoardPositions.CollectionChanged += BoardPositionsOnCollectionChanged;
}


public object Clone() {
    ...
    gameBoard.Init()
    return gameBoard;
}

それはうまくいくはずです!

于 2013-02-28T08:00:59.993 に答える
0

あなたの問題はこの行です:

gameBoard.BoardPositions.CollectionChanged += BoardPositionsOnCollectionChanged;

BoardPositionsOnCollectionChangedは複製されるオブジェクトのメンバーであるため、呼び出されると「this」は古いオブジェクトになります。

代わりに、ctor でイベント ハンドラーを設定します。

于 2013-02-28T08:02:14.997 に答える