确保在 Dispose 调用了对 EventHandler 的订阅
Make sure a subscription to an EventHandler is called at Dispose
我在构造函数中订阅了一个 EventHandler,并在 Dispose 方法中取消了订阅。确保在 Dispose 取消订阅此事件对我来说很重要,即即使用户忘记调用 Dispose 也会调用它。
我添加了一个解构函数,它应该在用户忘记时调用 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();
}
}
使用工厂
如果您确实需要取消订阅您的活动,则需要调用 Dispose
。 (不要使用终结器,因为你没有非托管内存。)
为了确保你的客户得到处置(如果你不能相信人们使用using
),那么我建议你使用工厂。
这样做你将能够在依赖注入容器中注册你的工厂,当你的应用程序关闭时,将调用你的工厂的处理,因此你将能够在那里处理你创建的所有客户端.
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");
}
}
}
我在构造函数中订阅了一个 EventHandler,并在 Dispose 方法中取消了订阅。确保在 Dispose 取消订阅此事件对我来说很重要,即即使用户忘记调用 Dispose 也会调用它。
我添加了一个解构函数,它应该在用户忘记时调用 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();
}
}
使用工厂
如果您确实需要取消订阅您的活动,则需要调用 Dispose
。 (不要使用终结器,因为你没有非托管内存。)
为了确保你的客户得到处置(如果你不能相信人们使用using
),那么我建议你使用工厂。
这样做你将能够在依赖注入容器中注册你的工厂,当你的应用程序关闭时,将调用你的工厂的处理,因此你将能够在那里处理你创建的所有客户端.
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");
}
}
}