像这样调用定时器回调方法安全吗?

Is it safe to call timer callback method like this?

如果我在这个逻辑中有一些错误请纠正我(不是一些优雅的东西,比如摆脱构造函数初始化和使用 Init 方法代替 Poll)。到目前为止,我还没有使用定时器回调的经验。我希望代码是不言自明的。让我有点困惑的是一些异步事物(比如连接客户端创建)和更多代码的混合——不过,我只是重用了 IClient class,它不是我的:

    public async Task<WaitForLoanActivationDto> WaitForLoanActivation(string userName, string accountGuid, int timeout)
    {
        const int dueTime = 0;
        const int pollPeriod = 500;
        Poll<WaitForLoanActivationDto> state = new Poll<WaitForLoanActivationDto>
        {
            Client = await _rpcConnectionPool.GetClientAsync(userName),
            AutoResetEvent = new AutoResetEvent(false),
            StartTime = DateTime.Now,
            Timeout = timeout,
            Parameters = new Variant[] { accountGuid },
            Result = new WaitForLoanActivationDto { Active = false }
        };

        Timer timer = new Timer(new TimerCallback(WaitForLoanActivationCallback), state, dueTime, pollPeriod);
        state.AutoResetEvent.WaitOne();
        timer.Dispose(state.AutoResetEvent);

        if (state.ThreadException != null)
        {
            throw state.ThreadException;
        }

        return state.Result;
    }

    private void WaitForLoanActivationCallback(object state)
    {
        Poll<WaitForLoanActivationDto> pollState = (Poll<WaitForLoanActivationDto>)state;

        if (pollState.StartTime.AddMilliseconds(pollState.Timeout) >= DateTime.Now)
        {
            try
            {
                using (RPCReply reply = ResultHelper.Check(pollState.Client.ExecuteRemoteCommand(WaitForLoanActivationRpcName, pollState.Parameters)))
                {
                    pollState.Result.Active = reply[2].IDList["Active"].AsBoolean().Value;
                    VariantList statusList = reply[2].IDList["statuses"].List;
                    if (statusList.Count > 0)
                    {
                        var statuses = CustomerInformationConverter.GetStatusesList(statusList);
                        pollState.Result.Statuses = statuses.ToArray();
                    }
                    if (pollState.Result.Active)
                    {
                        pollState.AutoResetEvent.Set();
                    }
                }
            }
            catch (Exception ex)
            {
                pollState.Result = null;
                pollState.ThreadException = ex;
                pollState.AutoResetEvent.Set();
            }
        }
        else
        {
            pollState.AutoResetEvent.Set();
        }
    }

谢谢你们。 @ckuri,根据你的想法,我想出了下面的代码。不过,我没有使用 Task.Delay,因为据我所知,即使任务成功完成,它也会造成延迟 - 在它之后。我的案例 objective 是在 timeout 毫秒期间每 pollPeriod 毫秒执行一次 运行 RPC 方法。它是方法 returns Active == false - 继续轮询,否则 - return 结果。 RPC 执行时间可能需要超过 pollPeriod 毫秒,因此如果它已经 运行ning - 没有意义产生另一个任务。

    public async Task<WaitForLoanActivationDto> WaitForLoanActivation(string userName, string accountGuid, int timeout)
    {
        var cancellationTokenSource = new CancellationTokenSource();
        try
        {
            const int pollPeriod = 500;
            IClient client = await _rpcConnectionPool.GetClientAsync(userName);
            DateTime startTime = DateTime.Now;
            WaitForLoanActivationDto waitForLoanActivationDto = null;

            while (startTime.AddMilliseconds(timeout) >= DateTime.Now)
            {
                waitForLoanActivationDto = await Task.Run(() => WaitForLoanActivationCallback(client, accountGuid), cancellationTokenSource.Token);
                if (waitForLoanActivationDto.Active)
                {
                    break;
                }
                else
                {
                    await Task.Delay(pollPeriod, cancellationTokenSource.Token);
                }
            }

            return waitForLoanActivationDto;
        }
        catch (AggregateException ex)
        {
            cancellationTokenSource.Cancel();
            throw ex.InnerException;
        }
    }

    private WaitForLoanActivationDto WaitForLoanActivationCallback(IClient client, string accountGuid)
    {
        using (RPCReply reply = ResultHelper.Check(client.ExecuteRemoteCommand(WaitForLoanActivationRpcName, accountGuid)))
        {
            var waitForLoanActivationDto = new WaitForLoanActivationDto
            {
                Active = reply[2].IDList["Active"].AsBoolean().Value
            };
            VariantList statusList = reply[2].IDList["statuses"].List;
            if (statusList.Count > 0)
            {
                var statuses = CustomerInformationConverter.GetStatusesList(statusList);
                waitForLoanActivationDto.Statuses = statuses.ToArray();
            }
            return waitForLoanActivationDto;
        }
    }