1

重複の可能性:
イベントハンドラーはガベージコレクションの発生を停止しますか?

私はこのような1つのwp7アプリケーションを持っていました:

private void button1_Click(object sender, RoutedEventArgs e)
{
    GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
    watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
    watcher.Start();
}

void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
    Debug.WriteLine(e.Position.Timestamp.ToString());
}

ボタンを2回クリックすると、コンソールはタイムスタンプを2回出力します。しかし、ウォッチャーはローカル変数でした!どうしたの?そして、どうすればそれを混乱させることができますか?

4

2 に答える 2

8

watcherはローカル変数ですが、必ずしもオブジェクトに影響するわけではありません。あなたはGeoCoordinateWatcher開始するように頼みました-私はそれがそれ自体への参照を効果的に維持するか、または適切な場所にそれを隠しておくことを期待します。

ボタンをクリックしたら無効にするウォッチャーをインスタンス変数に保持して、古いボタンを破棄して新しいボタンを作成できるようにする必要があるようです。(なぜそれが役立つのかわかりません。)

編集:ここには2つの間違った答えがあるので、何かを片付けさせてください...イベント発行者(この場合はウォッチャー)はハンドラーデリゲートへの参照を持っています。これらのデリゲートがインスタンスメソッドを参照している場合(この場合のように)、そのメソッドを含むタイプのインスタンスへの参照があります。

 Event publisher => delegate => instance of type with handler method

つまり、パブリッシャーがガベージコレクションされていない限り(そしてイベントハンドラーがまだ存在している限り)、デリゲートに関連付けられているインスタンスを収集することはできません。パブリッシャー自体がガベージコレクションされるのを防ぐことはできません。

言い換えれば、 (おそらくメソッドで)GeoCoordinateWatcher「特別な」ことをしなかった場合、ガベージコレクションが行われる可能性があります。イベントハンドラーからイベントパブリッシャーへの暗黙の参照はありません。これにより、イベントハンドラーがその方法でガベージコレクションされるのを防ぎます。Start

于 2012-06-12T07:30:03.877 に答える
-2

イベントはまだ割り当てられているため、 GCは実際には収集しませんwatcher(つまり、GeoCoordinateWatcherインスタンスは引き続き参照されているため、GCによって収集されません)。ローカル変数がスコープ外であっても、インスタンスはまだ生きています。

イベントハンドラーを切り離すと、watcher_PositionChanged期待どおりに機能します。そうでない場合は、GeoCoordinateWatcherボタンがクリックされるたびに新しいインスタンスが作成され、場所が変更されたときに各インスタンスがイベントを呼び出します。

これは、インスタンスを作成したり、ローカルでイベントを割り当てたりするときに、さまざまな奇妙な問題の原因となることがあります。あなたのような場合、2つの可能な解決策があります:

  1. インスタンス変数を作成し、それを1回だけ行うようにしてください
  2. 新しいインスタンスを作成する前に、古いインスタンスを適切に破棄してください(ガベージコレクターに依存しない)
于 2012-06-12T07:34:53.313 に答える