不确定 C# 代码是否存在计时/竞争条件? (有.NET fiddle repo)

问题描述 投票:0回答:1

我正在尝试测试我的自定义 IProgress 正在做我期望它做的事情 -> 每秒“报告”当前状态。

所以我有一些代码,但它总是失败。但这是关键——只有当我测试用例中几乎没有任何代码时,它才会失败?我不知道如何真正解释这个。

如果我在测试中再添加一段代码(在 repo 中被注释掉).. 如果你取消注释它就可以工作。

就像..有些东西需要被解雇..但是在检查“断言”之前它还没有完成?

完整回购:https://dotnetfiddle.net/qXHzlx

代码如下:

// Arrange.
var reportValue = 0;
var progress = new TimerProgress<int>((int value) => reportValue = value);

await Task.Delay(TimeSpan.FromSeconds(2)); // Need to wait more than 1 second for the report to work.

// Act.
progress.Report(5);

// Assert.
reportValue.ShouldBe(5);

和习俗

TimerProgress

public class TimerProgress<T> : IProgress<T>
{
    private readonly TimeSpan _intervalInMilliseconds;
    private readonly IProgress<T> _progress;
    private DateTime? _lastReportedOn;

    public TimerProgress(Action<T> handler, double intervalInMillieconds = 1000)
    {
        if (intervalInMillieconds <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(intervalInMillieconds));
        }

        _intervalInMilliseconds = TimeSpan.FromMilliseconds(intervalInMillieconds);

        _progress = new Progress<T>(handler);

        _lastReportedOn = DateTime.UtcNow;
    }

    public void Report(T value)
    {
        var now = DateTime.UtcNow;

        if (now - _lastReportedOn > _intervalInMilliseconds)
        {
            // We're due for a report!
            _progress.Report(value);
        }

        _lastReportedOn = now;
    }
}

有了测试用例,我期望:

  • TimeProgress
    实例。
    Now
    是“记住的”。
  • 等待 2 秒。 (你很快就会明白为什么)
  • “报告”。现在检查
    remembered-now
    是否超过 1 秒。 应该是 因为我们等了2秒!所以现在,我们应该“报告”
  • Handler 被调用 .. 它“记住”了数字 5
  • 我们现在断言“5”最终被报道了。

所以我不断收到一个失败断言,说值是

0
,而不是
5

但是当我在测试中再添加一行代码时,那么现在的值是

5
.

这是关于时间或事件触发问题吗?

这是关于我的处理程序如何尝试更新处理程序的变量outside,这是 Bad™️?

编辑 1:人们的建议是说

Progress<T>
实际上在引擎盖下使用同步上下文 这就是问题所在?

c# .net handler
1个回答
0
投票

这个问题已经就这个问题进行了很好的讨论。

因为进度是在

SynchronizationContext
上跑的。所以他们建议不要在我自己的课堂上使用
Progress<T>
。相反,只需调用
Action<T>
directly 这意味着它将在您当前的上下文中发生。

例如(偷代码)

public class SynchronousProgress<T> : IProgress<T>
{
    private readonly Action<T> action;

    public SynchronousProgress(Action<T> action)
    {
        this.action = action;
    }

    public void Report(T value)
    {
        action(value);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.