【发布时间】:2020-01-31 14:00:36
【问题描述】:
我的理解是,事件的订阅者(消费者)总是有被泄露的风险(如果生产者的寿命更长)。如果我在静态方法中使用匿名 lambda 函数订阅(非静态)事件,如果我希望 lambda 与生产者一起存在,我不应该取消订阅?
有一个variant of the question(lambda 事件订阅会造成内存泄漏吗?)和this answer,引用:
另外,那个 lambda 表达式没有使用任何变量,所以它可能会通过一个没有目标的静态方法来实现......我假设你关心的真实情况有一个更有趣的 lambda 主体.
我将此解释为,如果 lambda 表达式使用来自目标 (this) 的变量,您可能必须取消订阅,但在静态方法中,this 不存在,因此问题。
我想到的具体代码来自this answer(见下文)。该答案的 cmets 建议您必须取消订阅以避免内存泄漏,但这真的是真的吗?究竟泄露了什么? Another answer 对于试图处理取消订阅的同一个问题,实际上添加了潜在的内存泄漏(通过将事件处理程序存储在可能无法清理的静态字典中)。
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)
{
...
}
};
}
【问题讨论】:
-
这不仅与
this有关,还与您的 lambda 捕获 的内容有关。 -
@dymanoid 这很有趣。所以在上面的例子中,
dataGrid在 lambda 中使用。这是否意味着dataGrid和columns都会使 lambda 保持活动状态?
标签: c# .net wpf memory-leaks