说我的代码在lambda expressions
中使用了多个using-blocks
。
我已经阅读了由于可能memory leaks
而取消订阅事件处理程序。
是否有必要在using-blocks
中执行此操作,因为using
确保对象被处置?
这样编码是一种不好的做法吗? (我发现它很方便,因为它将所有内容保持在一起,而不是让一个类充满不同的事件处理程序
using (BackgroundWorker w = new BackgroundWorker())
{
w.WorkerSupportsCancellation = true;
w.WorkerReportsProgress = true;
w.ProgressChanged += (f, g) =>
{
pbExport.Maximum = (int)g.UserState;
pbExport.Value = g.ProgressPercentage;
};
w.RunWorkerCompleted += (c, d) =>
{
if ((!d.Cancelled) && ((bool)d.Result))
{
MSG.Text = "Backup completed !";
}
else
{
MSG.Foreground = Brushes.Red;
MSG.Text = "Error";
}
};
w.DoWork += (a, b) =>
{
using (MySqlConnection cn = new MySqlConnection(Statics._CS))
{
try
{
cn.Open();
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.Connection = cn;
using (MySqlBackup mb = new MySqlBackup(cmd))
{
mb.ExportInfo.IntervalForProgressReport = 50;
mb.ExportProgressChanged += (h, i) =>
{
w.ReportProgress(i.CurrentTableIndex, i.TotalTs);
};
mb.ExportToFile("dbbackup");
}
}
b.Cancel = false;
b.Result = true;
}
catch (MySqlException)
{
b.Cancel = true;
b.Result = false;
w.CancelAsync();
}
}
};
w.RunWorkerAsync();
}
答案 0 :(得分:3)
这看起来不错。在线程仍在执行时,using
块将在调用Dispose
后立即调用RunWorkerAsync
。
答案 1 :(得分:1)
我使用这样的lambdas开始,并且一旦复杂性增加就将它们重构为方法。这段代码存在一些问题,但恕我直言,使用像这样的lambdas没有什么本质上的错误,因为它非常易读。
您不需要using
。由于您只启动BackgroundWorker
并且不等待它完成,因此使用将在它仍在运行时尝试Dispose()
它。可能是其他东西都提到w并保持活着,但是你却错过了清理的机会。
在调试时,任何尝试在lambda中使用编辑并继续的尝试都将失败。如果您借此机会将lambda转换为方法,则不会发生这种情况。
我认为你对ProgressChanged
和内部ExportProgressChanged
使用lambd只是完美的,但是RunWorkerCompleted
处于代码I'的最大端。期待。在我看来,DoWork
太大而不能成为一个lambda。将其重构为方法。
最后,这里有一个很好的机会来重构你所拥有的SqlBackupWorkerWithProgress
。这将巩固您的代码的使用。
答案 2 :(得分:0)
foreach(var eventHandler in MyEvent)
eventHandler.Dispose()
处置资源始终是资源持有者的责任;事件持有者有责任确保事件处理人员得到妥善处理(见上文)
我不会对事件使用如此大的内联函数,我宁愿创建一个单独的函数。大lambdas是一个眼睛。
答案 3 :(得分:0)
您不应该以这种方式使用Block for BackgroundWorker。在您的示例中,工作程序将在RunWorkerAsync调用之后立即处理,可能导致后台处理停止。
声明一个属性以保持对BackgroundWorker的引用。在RunWorkerCompleted处理程序中将worker和set属性置为null。
由于事件提供程序保留对事件订阅者的引用,导致事件订阅者在事件提供者处于活动状态时不被垃圾回收,因此可能发生内存泄漏。
在该特定样本中,无需取消订阅事件,因为订阅者(处理事件的表单/代码)的寿命应该比后台工作者长。
答案 4 :(得分:0)
如果你的lambda没有在使用范围之外(或更广泛的局部变量范围)使用/引用/关闭,那么它们不会导致内存泄漏。
当您向后执行操作时会导致内存泄漏 - 您创建一个对象,在lambda中引用它(以及它上面的机箱),然后将其添加(并引用)给事件处理程序。
即。具有事件处理程序的任何对象都保存对其事件处理程序中所有labmdas的引用,并依次保存对这些lambdas中引用的所有对象的引用。