2016-07-08 4 views
6

Прямо к кодуСтранный эффект закрытия C# на сборщика мусора

class Program 
{ 
    private static WeakReference<EventHandler<EventArgs>> _noClosure; 
    private static WeakReference<EventHandler<EventArgs>> _closure; 

    static void Main(string[] args) 
    { 
     Init(); 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.Collect(); 
     EventHandler<EventArgs> target; 
     Console.WriteLine(_closure.TryGetTarget(out target)); 
     Console.WriteLine(_noClosure.TryGetTarget(out target)); 
    } 

    class C { public void Go() { } } 

    private static void Init() 
    { 
     _noClosure = new WeakReference<EventHandler<EventArgs>>((sender, args) => 
     { 
     }); 

     var s = new C(); 
     _closure = new WeakReference<EventHandler<EventArgs>>((sender, args) => 
     { 
       s.Go(); 
     }); 
    } 
} 

Выходом я получаю от этого кода

False 
True 

Как на земле это возможно?

P.S. Я вошел в это, пытаясь понять, как работает WeakEventManager.

ответ

6

Компилятор будет кэшировать делегата _noClosure в статическом поле и повторно использовать его каждый раз, когда вы вызываете Init. Точно такой же экземпляр можно повторно использовать каждый раз.

Сравните это с _closure, которое закрывается по новому экземпляру C() при каждом вызове Init() - это невозможно кэшировать.

Кэширование _noClosure означает, что у делегата есть сильная ссылка (поле), поэтому сбор мусора невозможен.

Если вы используете ildasm в своем приложении, вы можете увидеть все это в действии.

+0

Является ли эта деталь реализации, или это поведение указано (подразумевается) в документации где-нибудь? – ironic

+3

@ironic: факт, что он * делает *, является деталью реализации. Тот факт, что он * может * произойти, находится в спецификации. (В нем говорится, что один и тот же делегат может быть использован повторно). –

 Смежные вопросы

  • Нет связанных вопросов^_^