如何在Blazor应用程序中使计时器防泄漏?

如何在Blazor应用程序中使计时器防泄漏?,blazor,blazor-webassembly,Blazor,Blazor Webassembly,我在stackoverflow上发布了一个问题的答案。答案如下: 您可以创建一个计时器服务,它可以在多种情况下为您服务: 创建服务类: public class BlazorTimer { private Timer _timer; internal void SetTimer(double interval) { _timer = new Timer(interval); _timer.E

我在stackoverflow上发布了一个问题的答案。答案如下:

您可以创建一个计时器服务,它可以在多种情况下为您服务:

创建服务类:

public class BlazorTimer
    {
        private Timer _timer;

        internal void SetTimer(double interval)
        {
            _timer = new Timer(interval);
            _timer.Elapsed += NotifyTimerElapsed;
            _timer.Enabled = true;
            _timer.Start();
        }

        private void NotifyTimerElapsed(object sender, ElapsedEventArgs e)
        {
            OnElapsed?.Invoke();
        }

        public event Action OnElapsed;
    }
将服务添加到Program.Main方法中的DI容器中,作为瞬态:

builder.Services.AddTransient(config =>
        {
            var blazorTimer = new BlazorTimer();
            blazorTimer.SetTimer(1000);
            return blazorTimer;
        });
用法 然而,有人告诉我

BlazorTimer正在泄漏计时器。计时器是可识别的

取消订阅Blazor组件中实现的Dispose方法中的事件处理程序是否会导致
BlazorTimer泄漏了计时器。事实上,我并不完全理解“BlazorTimer正在泄漏_timer.timer是IDisposable的”,所以让我问一下,如何防止计时器泄漏,同时使用代码取消订阅Blazor组件中实现的Dispose方法中的事件处理程序?除了跳过事件处理程序的取消订阅之外,还有什么方法可以防止此泄漏。

BlazorTimer应该实现IDisposable。BlazorTimer Dispose方法应停止计时器,取消订阅已用事件,然后处置计时器


问题的根源在于BlazorTimer被设置为临时服务。因此,对于每个新请求,您将获得新的BlazorTimer对象和新的.Net计时器,这些计时器永远不会得到正确处理

BlazorTimer应该实现IDisposable。BlazorTimer Dispose方法应停止计时器,取消订阅已用事件,然后处置计时器


问题的根源在于BlazorTimer被设置为临时服务。因此,对于每个新的请求,您都会得到新的BlazorTimer对象和新的.Net计时器,这些计时器永远不会得到正确的处理

一般的经验法则是每次封装 一次性类型在新类型中作为成员,您应该 也可以一次性输入。在您的特定情况下,BlazorTimer类是 不是一次性的-因此,当 初始化,永远不会被处理-留下一些内存

此外,每次调用SetTimer方法时,都会有一个新的计时器 实例正在创建,而旧的实例正在被丢弃(在 空气),再次泄漏内存。考虑现有的处理 举个例子,如果这是你的意图的话。或者,更好的是,重用现有的 如果您的业务规则可以接受,请举例说明

注意:“BlazorTimer类不是一次性的”,因为我使用的是瞬态依赖项。将其作为一次性使用将产生不利影响。。。见说明


为了解决内存泄漏问题,在我当前的代码片段中,我应该简单地从NotifyTimeRecursed方法调用Timer对象上的Dispose方法(总是这样做,这次忘记了它)

好的,我已经解决了这个问题,这要感谢和

一般的经验法则是每次封装 一次性类型在新类型中作为成员,您应该 也可以一次性输入。在您的特定情况下,BlazorTimer类是 不是一次性的-因此,当 初始化,永远不会被处理-留下一些内存

此外,每次调用SetTimer方法时,都会有一个新的计时器 实例正在创建,而旧的实例正在被丢弃(在 空气),再次泄漏内存。考虑现有的处理 举个例子,如果这是你的意图的话。或者,更好的是,重用现有的 如果您的业务规则可以接受,请举例说明

注意:“BlazorTimer类不是一次性的”,因为我使用的是瞬态依赖项。将其作为一次性使用将产生不利影响。。。见说明


为了解决内存泄漏问题,在我当前的代码片段中,我应该简单地从NotifyTimeRecursed方法调用Timer对象上的Dispose方法(总是这样做,这次忘记了它)

“BlazorTimer应该实现IDisposable”请解释一下为什么。。。“仅当类型直接使用非托管资源时,才应实现IDisposable。”()。我是否直接使用“非托管资源?”“因此,对于每个新请求,您都会得到新的BlazorTimer对象和新的.Net计时器”,我知道这一点。“从未正确处理”问题是:我如何知道或验证新BlazorTimer对象“从未正确处理”您说:“BlazorTimer应该实现IDisposable”。但我读到“如果类不实现IDisposable,则只将它们注册为临时依赖项,否则,您的应用程序将泄漏内存。”我猜这意味着我的应用程序没有泄漏,对吗?采纳你的建议只会伤害我的应用程序,而不会改进我的应用程序。如果这实际上是框架处理瞬态的方式,那么这是微软应该解决的一个严重问题。这真的意味着您永远不能将IDisposable用作临时服务,这不是可接受的,更不是直观的。Microsoft应以这样一种方式处理作用域,即当您注入服务的页面被释放时,会自动调用Dispose,感谢您让我意识到框架中的这一限制。“BlazorTimer应实现IDisposable”请您解释一下为什么。。。“仅当类型直接使用非托管资源时,才应实现IDisposable。”()。我是否直接使用“非托管资源?”“因此,对于每个新请求,您都会得到新的BlazorTimer对象和新的.Net计时器”,我知道这一点。“从未正确处理”问题是:我如何知道或验证新BlazorTimer对象“从未正确处理”您说:“BlazorTimer应该实现IDisposable”。但我读到“如果类不实现IDisposable,则只将它们注册为临时依赖项,否则,您的应用程序将泄漏内存。”我猜这意味着我的应用程序没有泄漏,对吗?采纳你的建议只会伤害,而不会改进我的应用程序
@page "/"

@implements IDisposable
@inject BlazorTimer Timer

@count.ToString()


@code{
private int count = 0;

protected override void OnInitialized()
{
    Timer.OnElapsed += NotifyTimerElapsed;

    base.OnInitialized();
}

private void NotifyTimerElapsed()
{
    // Note: WebAssembly Apps are currently supporting a single thread, which 
    // is why you don't have to call
    // the StateHasChanged method from within the InvokeAsync method. But it 
    // is a good practice to do so in consideration of future changes, such as 
    // ability to run WebAssembly Apps in more than one thread.
    InvokeAsync(() => { count++; StateHasChanged(); });
}

public void Dispose()
{
    Timer.OnElapsed -= NotifyTimerElapsed;
}

}