Как безопасно утилизировать экземпляр клиента, возвращенный из синглтона?

#c# #asp.net-core #singleton #dispose

#c# #asp.net-core #синглтон #утилизировать

Вопрос:

Учитывая, что у меня есть следующий код, который предоставляется в виде одноэлементного пожизненного сервиса.net core, как я могу безопасно утилизировать клиент (он реализует IDisposable) и создать новый. Я обеспокоен тем, что как только я вызову Dispose старого клиента, он будет удален, и тем временем все вызывающие, которые извлекли клиент, будут указывать на клиент, который теперь удален.

 public class MyClientFactory: IMyClientFactory
{
    private Client { get; set; }

    public async Task<IMyClient> GetClient()
    {
        if (this.Client != null amp;amp; DoSomeChecksToSeeIfValid())
        {
            return this.Client;
        }
        else
        {
            this.Client?.Dispose();

            this.Client = new MyClient(await DoSomethingToGetNewCredentials());

            return this.Client;
        }
    }
}
 

Ответ №1:

Если вы хотите контролировать время жизни, лучше не возвращать экземпляр объекта. Но если это вас не устраивает, вы можете использовать модель событий.

 public interface IMyClientManager
{
     void Do(Action<MyClient> action);
}
public interface IMyClient : IDisposable
{
    
}
public sealed class MyClient: IMyClient
{
    public delegate void DisposeHandle();

    public event DisposeHandle DisposeEvent;

    private bool _isDispose;
    public void Dispose()
    {
        if (!_isDispose)
            DisposeEvent?.Invoke();
        _isDispose = true;
    }
}

public class MyClientManager : IMyClientManager
{
    private MyClient Client { get; set; }
    private object _sync = new object();
    private bool DoSomeChecksToSeeIfValid()
    {
        return this.Client != null;
    }

    public void Do(Action<MyClient> action)
    {
        // you can  create connection pull
        while (!DoSomeChecksToSeeIfValid())
        {
            InitClient();
            //todo: connect or setup
        }

        action.Invoke(this.Client);
    }

    private void InitClient()
    {
        if (this.Client == null)
        {
            lock (_sync)
            {
                this.Client ??= new MyClient();
                this.Client.DisposeEvent  = Client_DisposeEvent;
            }

        }
    }

    public MyClient Create()
    {
        // you can  create connection pull
        while (!DoSomeChecksToSeeIfValid())
        {
            InitClient();
            
        }

        return this.Client;
    }

    private void Client_DisposeEvent()
    {
        lock (_sync)
        {
            this.Client.DisposeEvent-= Client_DisposeEvent;
            this.Client = null;
        }

    }
}