有无数种方法可以解决这个问题。我首先想到的是使用在后台线程上启动的 Stopwatch 对象或 Timer 对象,然后编写一个可以订阅您感兴趣的事件的事件处理程序。当事件发生时,您的处理程序会触发,允许您暂停计时器并查询经过的时间,并相应地做出递增/重置决定。
这只是一个概念的非常粗略的草图,但应该会给你一些前进的想法。祝你好运。
根据上面@hatchet 的评论,这几乎开始听起来像一个带有“过期”成员的队列或一个“滑动窗口”事件视界,如果该评论准确反映了您的问题,您必须捕获该事件范围。
编辑作为我的边缘强迫症,我给了你最初的问题一些想法,并提出了一个可能与你的问题相关或可能不相关的概念,但至少对于学术练习,我将发布我的内容做过。在您的原始帖子中引起我注意的是过期或定时变量的概念,我认为这很新颖。您的问题指定您想要在给定的时间间隔过去时做一些特定的事情。
我试图将这个想法抽象成一个通用的形式,思考这样一个想法可能有用的几种方式。想到的一个想法是在游戏环境中,(例如)在“自毁”之前,玩家可能只能看到一条消息 20 秒。我可以想象将过期“管道”连接到类型中可能会非常方便。另一种情况可能是在 CAI 环境中,其中 System.Drawing.Image 应该只显示固定时间,然后消失 - 同样,内置到期和计时代码的情况可能很有用。
因此,至少考虑到这么多概念上的实用性,我开始工作,我拼凑的东西(我不会假装它全面或完整)是 Expiring 类型的泛型,表示为Expiring<T>
. 我整理的基线代码如下:
// First stab at an "expiring" type that is only valid for a set interval.
public class Expiring<T>
{
public delegate void ExpiredHandler(object sender, EventArgs e);
public event ExpiredHandler OnExpired;
T instance;
int signaledCount = 0;
long milliseconds = 0;
bool isExpired = false;
bool exceptOnExpiredReference = true;
System.Timers.Timer lapseTimer = new System.Timers.Timer();
public Expiring(T value)
{
instance = value;
}
public virtual void TimerElapsed(object sender, System.Timers.ElapsedEventArgs args)
{
if (OnExpired != null)
{
OnExpired(this, null);
}
isExpired = true;
}
public Expiring(T startValue, long expirationInterval, bool throwElapsedReferenceException):this(startValue)
{
milliseconds = expirationInterval;
lapseTimer.AutoReset = true;
lapseTimer.Interval = milliseconds;
exceptOnExpiredReference = throwElapsedReferenceException;
lapseTimer.Elapsed+=new System.Timers.ElapsedEventHandler(TimerElapsed);
this.Set();
}
public void Set()
{
signaledCount++;
lapseTimer.Stop();
lapseTimer.Start();
}
public T Value
{
get
{
if (!isExpired || !exceptOnExpiredReference)
return instance;
else
throw new InvalidOperationException("Reference to an expired value.");
}
set
{
instance = value;
}
}
}
这里的想法是,有人可以声明一个Expiring<int>
,指定它的初始值、过期时间和一个值,以指示在过期间隔过后尝试访问实例的值是否应该抛出异常。当 expireInterval 过去时,引发 OnExpired 事件,允许声明者指定自定义事件处理程序以在值到期时提供自定义操作。
如果调用者希望重置过期计时器,他只需要调用对象的 Set() 方法。这也增加了我最终没有使用的内部“signaledCount”值,但在确定到期计时器被重置的次数方面正在考虑。如果在过期间隔过后访问对象的 Value 属性,则会引发 InvalidOperationException 并显示“Value has expired”消息。
不幸的是,这个想法的理论/学术价值多于实际价值,恐怕。如果可以将所有算术运算符重载到本机值类型的实现中,它将具有更多的实用性,但我很快发现 C# 根本不喜欢这个概念(并在此处发现关于这个主题的相当广泛的帖子在这里)。理想情况下,我很想能够这样说:
Expired<Int32> foo = new Expired<Int32>(5,10000,true);
Expired<Int32> bar = new Expired<Int32>(10,10000,true);
Expired<Int32> baz = foo+bar; // can't make that work
有人认为这个问题可以通过动态类型来解决,但我现在选择不去追求它。正如我敲定的那样,这个想法供讨论,因为它适用于 OP 的“定时变量”概念的一般视图。鼓励和欢迎建设性的评论/批评/改进。