2017-01-08 18 views
0

Я рассматриваю здесь прототип медиатора https://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/.WPF WeakReference и GC

Автор указывает, что «Моя первая мысль заключалась в том, чтобы хранить ссылку на действие в режиме WeakReference. Поскольку сборщик мусора будет выбрасывать объекты, на которые ссылаются только объекты WeakReference, казалось бы, это сделало бы трюк К сожалению, это не так просто. Проблема с этим подходом заключается в том, что GC отбросит экземпляр Action, потому что на него ссылается только WeakReference! "

Мой вопрос вместо того, чтобы использовать «ссылку на действие», почему «ссылка на MethodInfo» делает трюк? Я предполагаю, что методinfo также должен быть собран.

Заранее спасибо.

+0

@Rob да, я согласен с вашим последним предложением. Однако то, что я сбиваю с толку, так это то, что автор подразумевал, что Action будет GCed, если вы сохраните ссылку на него в WeakReference (правильно ли я?), Поэтому зачем хранить ссылку на MethodInfo? –

ответ

1

Мой вопрос вместо того, чтобы использовать «ссылку на действие», почему «ссылка на MethodInfo» делает трюк? Я предполагаю, что методinfo также должен быть собран.

Нет, это на самом деле не MethodInfo против Action, что делает трюк. Это что-то еще, но я должен признать, что эта статья не очень хорошо написана и может ввести в заблуждение. Позвольте мне попытаться объяснить.

События и GC

Скажем, у вас есть класс с событием называется Click. Класс: Button Допустим, у вас есть еще один класс, который подписывается на событие от Button, как это:

public class Subscriber1 
{ 
    public Subscriber1(Button button) 
    { 
     button.Click += ClickHander; 
    } 

    private void ClickHander(object sender, EventArgs e) 
    { 
     // ... 
    } 

    public void UnSubscribe() 
    { 
     button.Click -= ClickHandler; 
    } 
} 

Теперь, как класс кнопки знаю, кто уведомить при нажатии на кнопку? Ну, он держит ссылку на все те классы, которые подписались. Таким образом, в вышеприведенном случае будет содержаться ссылка на экземпляр класса Subscriber1. Всякий раз, когда нажимается кнопка, он будет уведомлять экземпляр Subscriber1. Так что же произойдет, если мы делаем это:

subcriber1Instance = null; 

Что будет происходить в том, что если экземпляр button еще жив, GC не будет собирать subscriber1Instance. Зачем? Потому что он коренится: экземпляр button содержит ссылку на него. Вот почему мы должны делать это вместо:

subscriber1Instance.UnSubscribe(); 
subcriber1Instance = null; 

В действительности Subscriber1 должны осуществлять IDisposable и делать отписки там, но смысл этого ответа не так. Поэтому я сохраняю это просто, поэтому мы не теряем фокус.

Когда мы отменили подписку на событие Click экземпляра button, то subscriberIntance больше не укоренен и его можно очистить GC.

Так что же делать?

В этой статье авторы пытаются решить эту проблему разработчиков, забывая отказаться от подписки и, таким образом, вызывая проблемы с утечкой памяти. Обратите внимание, что это один из способов: только если издатель переживает абонента, он будет поддерживать подписчика живым, а не наоборот.Поэтому, если издатель готов к GC, абонент не сможет сохранить его в живых.

В основном то, что говорят авторы, заключается в том, что абонент не должен подписываться на событие напрямую, поэтому он не приводит к тому, что button держит твердую ссылку на него. Вместо этого абонент должен получить от WeakReference и передать его на номер button при подписке. Как это:

private class WeakSubscriber1 : WeakReference 
{ 
    public WeakSubscriber1(Subscriber1 target) : base(target) { } 

    public void ClickHander(object sender, EventArgs args) 
    { 
     Subscriber1 b = (Subscriber1)this.Target; 

     if (b == null) 
     { 
      Button c = sender as Button; 

      if (c != null) 
      { 
       c.MyEvent -= new EventHandler(this.ClickHandler); 
      } 
     } 

     else 
     { 
      b.Handler1(sender, args); 
     } 
    } 
} 

Для использования выше будет выглядеть так:

Subscriber1 sub1 = new Subscriber1(); 
WeakSubscriber1 weak = new WeakSubscriber1(sub1); 
Button button = new Button(); 
button.Click += weak.ClickHandler(); 

Теперь button холдинговая слабую ссылку. Это означает, что когда sub1 сделано нулевым, а button запускает событие, то weak проверит, sub1 - null. Если да, тогда он проверяет, жив ли еще button. Если оба значения истинны, то они будут отписаны. Теперь sub1 больше не подписывается на button.Click, поэтому GC может его собрать.

+0

Роб у вас есть шанс прочитать статью, связанную в этой статье? Это [здесь] (https://blogs.msdn.microsoft.com/greg_schechter/2004/05/28/simulating-weak-delegates-in-the-clr/). Разница заключается в том, что первая статья пытается использовать ту же идею, но в шаблоне посредника. По крайней мере, это то, что я собрал, когда прочитал их оба. Благодарю. – CodingYoshi

+0

@CodingYoshi спасибо для вашего подробного объяснения. Теперь я полностью понимаю, что пытался сделать автор. Но то, что я сбиваю с толку, заключается в том, что автор подразумевал, что Action будет GCed, если вы сохраните ссылку на него в WeakReference, поэтому почему сохранение ссылки на MethodInfo работает, не должно ли оно быть GCed? –