处理作用域方法

Disposing scoped methods

BinanceSpotClient 实例化 BinanceClientBinanceSocketClient。当 LiveTradeManager 完成执行时,它们必须被释放。我在 Dispose 方法上放置了一个断点,但它目前没有执行。我是否必须通过让 LiveTradeManager 继承 IDisposable 然后调用 BinanceSpotClient.Dispose 来手动调用它?

services.AddScoped<LiveTradeManager>();
services.AddScoped<PaperTradeManager>();
services.AddScoped<ITradeManagerFactory, TradeManagerFactory>();

services.AddScoped<IExchangeClientFactory, ExchangeClientFactory>();
public interface ITradeManager
{
    Task RunAsync();
}

public class LiveTradeManager : ITradeManager
{
    private readonly ILogger _logger;
    private readonly IExchangeClient _exchangeClient;

    public LiveTradeManager(ILogger logger, IExchangeClientFactory exchangeClientFactory)
    {
        _logger = logger;
        _exchangeClient = exchangeClientFactory.GetExchangeClient(exchangeOptions.Value.Exchange);
    }
    
    ...
}

public interface IExchangeClientFactory
{
    IExchangeClient GetExchangeClient(Exchange exchange);
}

public class ExchangeClientFactory : IExchangeClientFactory
{
    private readonly IServiceProvider _serviceProvider;

    public ExchangeClientFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IExchangeClient GetExchangeClient(Exchange exchange)
    {
        return exchange switch
        {
            Exchange.BinanceSpot => ActivatorUtilities.CreateInstance<BinanceSpotClient>(_serviceProvider) ?? throw new NullReferenceException(),
            _ => throw new ArgumentOutOfRangeException(nameof(exchange), exchange, null)
        };
    }
}

public class BinanceSpotClient : IExchangeClient, IDisposable
{
    private readonly ILogger _logger;
    private readonly IBinanceClient _client;
    private readonly IBinanceSocketClient _socketClient;

    public BinanceSpotClient(ILogger logger, IOptions<ExchangeOptions> exchangeOptions)
    {
        _logger = logger;

        _client = new BinanceClient(new BinanceClientOptions()
        {
            ApiCredentials = new ApiCredentials(exchangeOptions.Value.ApiKey, exchangeOptions.Value.SecretKey),
            AutoTimestamp = true,
            AutoTimestampRecalculationInterval = TimeSpan.FromMinutes(30),
            TradeRulesBehaviour = TradeRulesBehaviour.AutoComply
        });

        _socketClient = new BinanceSocketClient(new BinanceSocketClientOptions()
        {
            ApiCredentials = new ApiCredentials(exchangeOptions.Value.ApiKey, exchangeOptions.Value.SecretKey),
            AutoReconnect = true,
            ReconnectInterval = TimeSpan.FromSeconds(15)
        });
    }
    
    private bool _disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            if (_client != null)
            {
                _client.Dispose();
            }

            if (_socketClient != null)
            {
                _socketClient.UnsubscribeAll();
                _socketClient.Dispose();
            }

            _subject.OnNext(Observable.Never<Unit>());
        }

        _disposed = true;
    }
}

Do I have to manually call it by making LiveTradeManager inherit IDisposable and then call BinanceSpotClient.Dispose?

如果不想给容器注册IExchangeClient,基本可以。

正在考虑向 container 注册 IExchangeClient。如果容器不知道它,它就不能为你调用 Dispose。这意味着它成为你的工作。

显式工厂模式方法(您在此处使用的方法)的一般问题正是您遇到的问题。这就是为什么我更喜欢 Autofac 的方法 (https://autofaccn.readthedocs.io/en/latest/resolve/relationships.html / https://autofaccn.readthedocs.io/en/latest/advanced/delegate-factories.html) - 处理是容器的问题,所以你让容器 成为工厂 所以它知道什么时候需要处理

要理解的关键是,使用您当前的代码,容器知道工厂,但不知道工厂内部发生了什么. 可以查看代码并发现需要处理的内容,但容器不能。如果实现了IDisposable,容器将处理工厂——但不是工厂正在创建的东西.