【问题标题】:Should I dispose transient object provided by IServiceProvider or the garbage collector takes care of it?我应该处理 IServiceProvider 提供的瞬态对象还是垃圾收集器处理它?
【发布时间】:2021-05-19 09:57:57
【问题描述】:

我正在构建一个锦标赛应用程序,其中当然有很多锦标赛可以玩。我从 ASP.NET Core 3.1 中的内置依赖注入中获取了一个 TournamentStore 对象。

在 Startup.cs 中,在 ConfigureServices 方法中我设置了一个临时服务:

services.AddTransient<ITournamentStore, TournamentStore>();

我通过在 TournamentService 类的构造函数中注入 IServiceProvider 来获得该服务:

public class TournamentService : ITournamentService
{
    private readonly IServiceProvider _serviceProvider;

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

    public async Task<ITournamentStore> GetRandomTournamentAsync(DateTime startTime)
    {
        var tournament = (ITournamentStore)_serviceProvider.GetService(typeof(ITournamentStore));
        // add tournament details...

在 TournamentStore(我从 IServiceProvider 获得的服务)中,我正在使用 System.Timers.Timer,它应该被丢弃:

public class TournamentStore : ITournamentStore, IAsyncDisposable, IDisposable
{
    private Timer _timer;

    private readonly ITournamentsStore _tournaments;
    private readonly IHubContext<GameHub, IGameClient> _hubContext;
    private readonly IMapper _mapper;

    public TournamentStore(
        ITournamentsStore tournaments,
        IHubContext<GameHub, IGameClient> hubContext,
        IMapper mapper)
    {
        _tournaments = tournaments;
        _hubContext = hubContext;
        _mapper = mapper;
    }

    public string PublicId { get; set; } = Guid.NewGuid().ToString();
    public string Name { get; set; }
    public string Category { get; set; }
    public int? CategoryId { get; set; }
    public string Type { get; set; }
    public string TypeId { get; set; }
    public string Difficulty { get; set; }
    public string DifficultyId { get; set; }
    public List<QuestionModel> Questions { get; set; }
    public int NumberOfQuestions => Questions.Count();
    public int SecondsPerQuestion { get; set; } = 15;
    public int CurrentQuestion { get; set; } = 0;
    public bool Finshed => CurrentQuestion > Questions.Count();
    public bool Public { get; set; }
    public DateTime StartTime { get; set; }
    public string StartTimeWithTimeZone => StartTime.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
    public DateTime? EndTime { get; set; }
    public List<Player> Players { get; set; }
    public int NumberOfPlayers => Players.Count();

    public void SetTournamentStartTimer()
    {
        var difference = StartTime - DateTime.UtcNow;
        _timer = new Timer(difference.TotalMilliseconds);
        _timer.Elapsed += async (sender, e) => await StartTournamentAsync();
        _timer.Start();
    }

    private async Task StartTournamentAsync()
    {
        // some logic to start tournament

    }

    public ValueTask DisposeAsync()
    {
        throw new NotImplementedException();
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }

所以我想知道我应该在 DisposeAsync 方法中处理完整对象还是只处理 Timer 并让垃圾收集器处理 TournamentStore 对象? 正如您所看到的,TournamentStore 对象由多个属性和两个对象列表组成,所以如果我正在处理 TournamentStore 对象,我应该将这些列表设置为 null 吗? 如果没有足够的玩家或锦标赛结束,将从对象本身调用 DisposeAsync。

【问题讨论】:

    标签: c# asp.net-core


    【解决方案1】:

    向服务提供者请求 ITournamentStore 的类不知道对象的范围(单例、瞬态等),因此 TournamentStore 的处置应由 ServiceProvider 管理。

    TournamentStore 的所有可处置属性都应在 TournamentStore 处置时处置。 无需将所有属性都设置为null。

    我建议不要同时实现接口 IDisposable 和 IAsyncDisposable。 Dispose 或 DisposeAsync 方法旨在由创建 TournamentStore 的对象调用(此处为 ServiceProvider)。

    我建议使用如下实现:

    private async Task<ITournament> StartTournamentAsync()
    

    ITournament : IAsyncDisposable
    

    【讨论】:

    • 所以我应该只配置一个定时器?
    • 是的,因为 Timer 是 TournamentStore 创建的唯一一次性对象。每次调用 SetTournamentStartTimer 时都要小心创建一个新的 Timer。 _timer 属性应该是只读的并在构造函数中创建以避免创建多个计时器。
    猜你喜欢
    • 2012-12-29
    • 2011-03-29
    • 2014-01-06
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    相关资源
    最近更新 更多