[英]How do I fix a memory leak caused by an object referenced by a ContextMenuStrip
我已经使用dotMemory来定位内存泄漏。 事件处理程序通过ToolStripMenuItem和ContextMenuStrip引用了我想要的对象。 该对象包含以下属性:
public override ContextMenuStrip PopupMenu
{
get
{
ContextMenuStrip myPopup = new ContextMenuStrip();
myPopup.Items.Add(ItemDelete);
return myPopup;
}
}
public ToolStripMenuItem ItemDelete
{
get
{
ToolStripMenuItem itemDelete = new ToolStripMenuItem("Delete " + name);
itemDelete.Enabled = Deletable;
itemDelete.Image = Properties.Resources.del;
itemDelete.Click += ItemDelete_Click;
return itemDelete;
}
}
我简化了代码,弹出菜单中有大约十二个菜单项,在我使用弹出菜单删除对象后,所有这些菜单项似乎都保留在该对象上。 我尝试覆盖该对象的基本delete方法以删除处理程序,但这没有用。
public override void delete()
{
if (PopupMenu != null)
{
ItemDelete.Click -= ItemDelete_Click;
}
base.delete();
}
没有一个好的, 最小的 , 完整的代码示例 ,就不可能确定是什么问题,更不用说最好的解决方案了。 那说...
根据到目前为止您已发布的少量代码,您似乎已经滥用了C#中的属性功能,并且这样做使代码变得模糊不清,导致您无法识别该错误。 特别是,您的ItemDelete
属性每次调用时都会创建一个新对象,这是实现此类getter的一种可怕方法。 为了使代码正常工作,您必须注意只调用该属性getter一次,然后将结果手动缓存到其他位置。
在属性获取器中创建一个新对象并不是天生的坏事,但是只有当该对象将由属性获取器自身缓存并重新用于后续调用时,或者该对象在语义上是一个简单值(最好是实际值)时,才应执行此操作值类型,但也可以使用简单的,全变的引用类型),其中新创建的对象在功能上与任何先前创建的对象相同(即,它们可以互换使用而不会影响代码的正确性)。
鉴于上述情况 ,您可能会发现以下替代方法是解决问题的有用方法:
private Lazy<ToolStripMenuItem> _itemDelete =
new Lazy<ToolStripMenuItem>(() => _CreateItemDelete());
private ToolStripMenuItem _CreateItemDelete()
{
ToolStripMenuItem itemDelete = new ToolStripMenuItem("Delete " + name);
itemDelete.Enabled = Deletable;
itemDelete.Image = Properties.Resources.del;
itemDelete.Click += ItemDelete_Click;
return itemDelete;
}
public ToolStripMenuItem ItemDelete
{
get
{
return _itemDelete.Value;
}
}
这将延迟ToolStripMenuItem
对象的创建,直到第一次调用属性getter时,但是在随后的对该getter的调用中,它将返回在第一次调用中创建的对象。
这样,您将确保执行语句ItemDelete.Click -= ItemDelete_Click;
稍后,您实际上是从原始对象中删除事件处理程序,而不是从那时创建的某些新对象中删除事件处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.