扩展方法中的Lambdas:可能的内存泄漏?

Oli*_*ver 6 c# lambda extension-methods

我只是通过使用扩展方法回答了一个非常简单的问题.但在写完之后我记得你不能从事件处理程序取消订阅lambda.

到目前为止没有大问题.但是这一切如何在扩展方法中表现出来?

下面是我的代码再次剪断.所以任何人都可以启发我,如果你多次调用这个扩展方法会导致无数的计时器在内存中徘徊?

我会说不,因为定时器的范围在这个函数内是有限的.所以在离开后没有其他人有这个对象的引用.我只是有点不确定,因为我们在静态类中的静态函数中.

public static class LabelExtensions
{
    public static Label BlinkText(this Label label, int duration)
    {
        System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

        timer.Interval = duration;
        timer.Tick += (sender, e) =>
            {
                timer.Stop();
                label.Font = new Font(label.Font, label.Font.Style ^ FontStyle.Bold);
            };

        label.Font = new Font(label.Font, label.Font.Style | FontStyle.Bold);
        timer.Start();

        return label;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

只是为了澄清我使用的是System.Windows.Forms.Timer.所以从您的答案看来,特别是使用这个计时器类只是正确的选择因为它做了任何事情,就像我在这种情况下所期望的那样.如果你在这种情况下尝试另一个计时器类,你可能会遇到麻烦,正如马修发现的那样.此外,我发现了一种方法,通过使用了WeakReference ■如果我的对象是活着还是没有.

更新2

经过一点点的睡眠和更多的思考后,我还对我的测试仪做了另一个改动(下面回答)我刚刚GC.Collect()在最后一行之后添加了一个并将持续时间设置为10000.启动BlinkText()几次之后我一直按下我的按钮2到获取当前状态并强制进行垃圾回收.而且看起来所有的计时器都会调用Stop()方法后被销毁.因此,当我的BlinkText已经离开并且计时器正在运行时,垃圾收集也不会导致任何问题.

因此,经过你所有的良好反应和更多的测试后,我可以高兴地说,它只是做了它应该做的事情而不会将计时器留在记忆中,也不会在计时器完成工作之前扔掉它们.

Oli*_*ver 0

阅读完您的所有答案后,我找到了一种更好地测试它的方法。

我按以下方式更新了我的扩展类:

public static class LabelExtensions
{
    public static List<WeakReference> _References = new List<WeakReference>();

    public static Label BlinkText(this Label label, int duration)
    {
        Timer timer = new Timer();

        _References.Add(new WeakReference(timer));

        timer.Interval = duration;
        timer.Tick += (sender, e) =>
        {
            timer.Stop();
            label.Font = new Font(label.Font, label.Font.Style ^ FontStyle.Bold);
        };

        label.Font = new Font(label.Font, label.Font.Style | FontStyle.Bold);
        timer.Start();

        return label;
    }
}
Run Code Online (Sandbox Code Playgroud)

我还创建了第二个按钮、第二个标签,并将以下代码添加到单击事件中:

    private void button2_Click(object sender, EventArgs e)
    {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < LabelExtensions._References.Count; i++)
        {
            var wr = LabelExtensions._References[i];
            sb.AppendLine(i + " alive: " + wr.IsAlive);
        }

        label2.Text = sb.ToString();
    }
Run Code Online (Sandbox Code Playgroud)

现在我只需按几次第一个按钮即可让第一个标签闪烁。然后我按下第二个按钮并得到一个列表,我可以在其中查看我的计时器是否仍然有效。第一次点击时,他们都得到了正确的结果。但后来我再次点击第一个按钮几次,当我更新状态消息时,我看到第一个项目在 IsAlive 中已经出现错误。所以我可以有把握地说这个函数不会导致任何内存问题。