Может ли подписка на события с анонимной лямбой в статическом методе вызвать утечку памяти? - PullRequest
2 голосов
/ 02 октября 2019

Насколько я понимаю, подписчику (потребителю) события всегда грозит утечка (если производитель живет дольше). Если я подпишусь на (нестатическое) событие с помощью анонимной лямбда-функции внутри статического метода, мне не нужно будет отписываться, если я хочу, чтобы лямбда оставалась в живых до тех пор, пока живет производитель?

Существует вариант вопроса (Создает ли подписка на лямбда-события утечку памяти?) С этим ответом , цитируя:

Кроме того, лямбда-выражение не используетлюбые переменные из этого, так что это, вероятно, будет реализовано статическим методом без цели в любом случае ... Я предполагаю, что реальная ситуация, в которой вы заинтересованы, имеет более интересное лямбда-тело.

Я интерпретируюэто означает, что вам, возможно, придется отказаться от подписки, если лямбда-выражение использует переменные из цели (this), но в статическом методе this не существует, поэтому возникает вопрос.

Конкретныйкод, о котором я думаю, взят из этого ответа (см. ниже). Комментарии к этому ответу предполагают, что вы должны отказаться от подписки, чтобы избежать утечек памяти, но так ли это на самом деле? Что именно просочилось? Другой ответ на тот же вопрос, который пытался обработать отмену подписки, вместо этого фактически добавил потенциальную утечку памяти (сохраняя обработчики событий в статическом словаре, который не может быть очищен).

private static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    DataGrid dataGrid = source as DataGrid;
    ObservableCollection<DataGridColumn> columns = e.NewValue as ObservableCollection<DataGridColumn>;

    // There should be no need to unsubscribe to e.OldValue?

    dataGrid.Columns.Clear();

    if (columns == null)
    {
        return;
    }

    foreach (DataGridColumn column in columns)
    {
        dataGrid.Columns.Add(column);
    }

    // This event handler will not keep the columns alive, and the lambda will only be alive as long as the columns is alive?
    columns.CollectionChanged += (sender, e2) =>
    {
        NotifyCollectionChangedEventArgs ne = e2 as NotifyCollectionChangedEventArgs;
        if (ne.Action == NotifyCollectionChangedAction.Reset)
        {
            // Clear dataGrid.Columns
            ...
        }
        else if (ne.Action == NotifyCollectionChangedAction.Add)
        {
            // Add to dataGrid.Columns
            ...
        }
        else if (ne.Action == NotifyCollectionChangedAction.Move)
        {
            ...
        }
        else if (ne.Action == NotifyCollectionChangedAction.Remove)
        {
         ...
        }
        else if (ne.Action == NotifyCollectionChangedAction.Replace)
        {
          ...
        }
    };
}

1 Ответ

4 голосов
/ 02 октября 2019

Учитывая ответ, на который вы ссылались, и комментарий об утечке, вы должны отметить следующее.

В модели представления есть объект типа ObservableCollection<DataGridColumn>. В WPF модели представления могут жить дольше, чем их представления (например, вы можете переключать разные виды для одной и той же модели представления или можете поддерживать свою модель просмотра в течение всего времени и отображать соответствующее представление только при необходимости, например, подумайте о скрытом окне инструмента).

Этот объект viewmodel получает подписку на событие с лямбдой:

columns.CollectionChanged += (sender, e2) => { /* ... */ };

Сама лямбда захватывает элемент представления - dataGrid:

// lambda body
{
    // ...
    dataGrid.Columns.Clear();
}

Сейчас, у вас есть сильная цепочка ссылок: columns -> лямбда-объект -> dataGrid.

Это означает, что объект dataGrid будет жить до тех пор, пока существует объект columns. Как отмечалось выше, это объект модели представления, и он может жить все время, пока запущено приложение. Таким образом, dataGrid продолжит жить, даже если соответствующий вид больше не будет виден и не имеет других ссылок.

Это утечка, о которой они говорят.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...