2011-02-09 14 views
0

たとえば、は、タイマーがガベージコレクションされないように、ここで行うようにタイマーインスタンスをリストに追加する必要がありますか?コールバックが匿名でない場合、aswerはyesですが、匿名であるため、匿名メソッドブロックでアクセス可能なメソッドブロックの変数は、匿名メソッドが完了したときにのみガベージコレクションされると思いますか?この場合、私が行っているようにREFを保存する必要はありません。:匿名メソッドでアクセス可能なメソッド変数はいつガベージコレクションされますか?

private static List<Timer> timers = new List<Timer>(); 

public static void RunCallbackAfter(Action callback, int secondsToWait) 
{ 
     Timer t = null; 
     t = new Timer(new TimerCallback(delegate(object state) 
      { 
       SomeThread.BeginInvoke(callback); 
       timers.Remove(t); 
      }), null, secondsToWait*1000, Timeout.Infinite); 
     timers.Add(t); 
} 

答えて

2

匿名メソッドで作成されたデリゲートがガベージコレクションに適格になるまで、匿名メソッドでキャプチャされた変数によって参照されるオブジェクトは、ガベージコレクションの対象になりません。

それはデリゲートへの参照を持っており、他に何もタイマーへの参照を持っていないだけTimerだ場合は、その後、私はこれが実際にタイマーの一種であると仮定すると、両方がガベージコレクションの対象となり疑いますそれを参照する必要があります。 (私はいくつかのタイマーがこれを必要としますことを覚えているようだし、いくつかをしません。私はこれはどの覚えていないことができます。)

また、あなたがそれを匿名メソッド内からtimers.Remove(t)コールを削除した場合最初にtをキャプチャしないでしょう。唯一のキャプチャ寿命が長い...ないすべて匿名メソッドを含むメソッドの変数。

0

いいえタイマーを隠す必要はありません。それは通常、あなたの代理人によって参照されるだけなので、ガベージコレクションされます。しかし、私は、Timerコンストラクタは基本的なランタイムとの参照を配置すると信じています。

エリックリペットは、おそらく彼のブログの記事で言いたいことがあります:The implementation of anonymous methods in C# and its consequences (part 1)

あなたTimer変数tあなたの匿名メソッドへの参照がある限り、アクセス可能のままになります。あなたの匿名の方法は、イベントが発生するまで参照されたままになります。少なくともそれは長い。

Eric Lippertによれば、c#コンパイラは、メソッドのコンテキスト(囲みオブジェクトのthisを含む)をすべて独自の小さなコンパイラ生成クラスでラップして、コードを何かに変えます。だから、匿名のメソッド(または代理人)自身がタイマーへの参照を含んでいるようです。

ああ、このスレッドの他の人はすべて正しいです:私はちょうど何かをぼかしました(そして、C#コンパイラが匿名メソッドを同時にどのように扱うかについて学びました)。

はい、あなたは循環参照を持っています。しかし、私はかなりタイマーを作成することは、ランタイム/ウィンドウのどこかにそれをフックする必要があります確信しています。チェックしましょう。

リフレクターを使用すると、System.Timer.Timer()からTimerBaseまでのトレイルに従うことができます。このトレイルは、externメソッドAddTimerNativeです。私はそれをどのように覗いているのか分かりませんが、OSにタイマーを登録すると確信しています。

結論:あなたのタイマーは、発火するまでOSによって参照されるため、有効範囲外にはなりません。

+0

huh? – markmnl

+0

ああ誇張してください。_closure_は、匿名メソッド – markmnl

+1

からアクセス可能な変数の名前ですが、コールバックとタイマーは循環参照を形成します。コールバックへの外部参照があった場合、問題はありません(ただし、それがクロージャー内にあることを確認するために外部変数に触れなければならないことを除いて)... – bdonlan

0

一般に、C#の匿名関数は、anon関数自体が破棄されるまでを参照するローカル変数を保持します。当然のことながら、この場合remove呼び出しを削除すると、参照が削除されます。つまり、変数がコールバックによって保持されなくなります。

ただし、ここでは循環参照を構成しています。外部参照がない限り、タイマーとコールバックは同時に破棄される可能性があります。私はタイマーを開始することは、C#でそれを生き続ける外部参照としてカウントするかどうかわからないので、私はあなたの質問に完全に答えることはできません。開始されたタイマーが外部参照を持つものとして扱われると、それだけでタイマーとコールバックの両方が有効になります。

関連する問題