确保在DISPOSE上订阅EventHandler

发布于 2025-01-25 14:30:55 字数 891 浏览 4 评论 0原文

我正在订阅构造函数中的EventHandler,并在Dispose方法中取消订阅。对我而言,重要的是要确保此事件在Dispose时取消订阅,即使用户忘记调用它,也可以调用IE处置。

我添加了一个解构器,如果用户忘记了,它应该调用Dispose方法,但是当我对其进行断点时,似乎并没有。

// Program.cs
// this scope is on purpose to make sure it's disposed
{
    var client = new DeribitClient(DeribitEndpointType.Productive);
}

Console.ReadLine();

// Client.cs
public sealed class Client : IDisposable
{
    private readonly WebSocketClient _client;

    public Client()
    {
        _client = new WebSocketClient("wss://...");
        _client.MessageReceived += OnMessageReceived;
    }

    public void Dispose()
    {
        _client.MessageReceived -= OnMessageReceived;

        GC.SuppressFinalize(this);
    }

    private void OnMessageReceived(object? sender, MessageReceivedEventArgs e)
    {
    }

    ~Client()
    {
        Dispose();
    }
}

I'm subscribing to an EventHandler in the constructor and unsubscribing it in the Dispose method. It's important for me to make sure this event is unsubscribed at Dispose, i.e. Dispose is called even if the user forgets calling it.

I added a deconstructor which is supposed to call the Dispose method if the user forgets to, but when I put a breakpoint at it, it doesn't seem like it does.

// Program.cs
// this scope is on purpose to make sure it's disposed
{
    var client = new DeribitClient(DeribitEndpointType.Productive);
}

Console.ReadLine();

// Client.cs
public sealed class Client : IDisposable
{
    private readonly WebSocketClient _client;

    public Client()
    {
        _client = new WebSocketClient("wss://...");
        _client.MessageReceived += OnMessageReceived;
    }

    public void Dispose()
    {
        _client.MessageReceived -= OnMessageReceived;

        GC.SuppressFinalize(this);
    }

    private void OnMessageReceived(object? sender, MessageReceivedEventArgs e)
    {
    }

    ~Client()
    {
        Dispose();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

灼痛 2025-02-01 14:30:55

则使用工厂

如果您确实需要取消订阅, ,则需要处置要被调用。 (不要使用最终确定器,因为您没有不受管理的内存。)

确保您的客户被处置(如果您不能相信人们使用>),那么我建议您使用工厂。

这样做,您将能够在依赖项注入容器中注册工厂,当您的申请关闭时,将调用工厂的处置,因此您将能够在那里处置所有创建的客户。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var hostBuilder = CreateHostBuilder(args);
            using var host = hostBuilder.Build();
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);
            hostBuilder = hostBuilder.ConfigureServices((services) =>
            {
                services.AddSingleton<ClientFactory>();
                services.AddHostedService<MyHostedService>();
            });
            return hostBuilder;
        }
    }


    internal class MyHostedService : BackgroundService
    {
        private readonly ClientFactory _clientFactory;
        private readonly IHostApplicationLifetime _hostApplicationLifetime;

        /// <summary>
        /// Constructor used by dependency injection.
        /// </summary>
        public MyHostedService(ClientFactory clientFactory, IHostApplicationLifetime hostApplicationLifetime)
        {
            _clientFactory = clientFactory;
            _hostApplicationLifetime = hostApplicationLifetime;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var client1 = _clientFactory.GetClient();
            // Oups I forgot to dispose my client

            // Self destruction
            Thread.Sleep(1000);
            _hostApplicationLifetime.StopApplication();
            return Task.CompletedTask;
        }
    }

    internal class ClientFactory : IDisposable
    {
        private List<Client> _clients = new List<Client>();

        public void Dispose()
        {
            foreach (var client in _clients)
            {
                client.Dispose();
            }
            _clients.Clear();
        }

        public Client GetClient()
        {
            var client = new Client();
            _clients.Add(client);
            return client;
        }
    }

    internal class Client : IDisposable
    {
        public void Dispose()
        {
            // Unsubscribe your event here
            // ...
            Console.WriteLine("Client has been disposed");
        }
    }
}

Use a factory

If you really need to have your event unsubscribed, you need Dispose to be called. (Don't use the finalizer because you don't have unmanaged memory.)

To ensure that your clients are disposed (if you can't trust people to use using), then I would advise you to use a factory.

Doing so you will be able to register your factory in a dependency injection container, and when your application closes, the dispose of your factory will be called, so you will be able to dispose there all the clients you have created.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var hostBuilder = CreateHostBuilder(args);
            using var host = hostBuilder.Build();
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);
            hostBuilder = hostBuilder.ConfigureServices((services) =>
            {
                services.AddSingleton<ClientFactory>();
                services.AddHostedService<MyHostedService>();
            });
            return hostBuilder;
        }
    }


    internal class MyHostedService : BackgroundService
    {
        private readonly ClientFactory _clientFactory;
        private readonly IHostApplicationLifetime _hostApplicationLifetime;

        /// <summary>
        /// Constructor used by dependency injection.
        /// </summary>
        public MyHostedService(ClientFactory clientFactory, IHostApplicationLifetime hostApplicationLifetime)
        {
            _clientFactory = clientFactory;
            _hostApplicationLifetime = hostApplicationLifetime;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var client1 = _clientFactory.GetClient();
            // Oups I forgot to dispose my client

            // Self destruction
            Thread.Sleep(1000);
            _hostApplicationLifetime.StopApplication();
            return Task.CompletedTask;
        }
    }

    internal class ClientFactory : IDisposable
    {
        private List<Client> _clients = new List<Client>();

        public void Dispose()
        {
            foreach (var client in _clients)
            {
                client.Dispose();
            }
            _clients.Clear();
        }

        public Client GetClient()
        {
            var client = new Client();
            _clients.Add(client);
            return client;
        }
    }

    internal class Client : IDisposable
    {
        public void Dispose()
        {
            // Unsubscribe your event here
            // ...
            Console.WriteLine("Client has been disposed");
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文