C# Windows 8.1中的计时器-如何模拟计时器(TimerCallback)构造函数?
我正在将现有的.NET类库移植到针对Windows 8.1的Windows应用商店应用程序。C# Windows 8.1中的计时器-如何模拟计时器(TimerCallback)构造函数?,c#,timer,windows-store-apps,windows-8.1,C#,Timer,Windows Store Apps,Windows 8.1,我正在将现有的.NET类库移植到针对Windows 8.1的Windows应用商店应用程序。Timer类可用,但与相应的.NET FrameworkTimer相关的一些选项似乎缺失 特别是,Windows应用商店版本中只有两个构造函数可用: public Timer(TimerCallback callback, Object state, int dueTime, int period); public Timer(TimerCallback callback, Object state, T
Timer
类可用,但与相应的.NET FrameworkTimer
相关的一些选项似乎缺失
特别是,Windows应用商店版本中只有两个构造函数可用:
public Timer(TimerCallback callback, Object state, int dueTime, int period);
public Timer(TimerCallback callback, Object state, TimeSpan dueTime, TimeSpan period);
.NET Framework包含此附加构造函数:
public Timer(TimerCallback callback);
根据设置
dueTime
和period
到Timeout.Infinite
和state
到计时器
对象本身
尝试替换单参数构造函数时,我“天真地”尝试将计时器
对象传递到一个Windows 8.1构造函数中,如下所示:
Timer t;
t = new Timer(MyCallback, t, Timeout.Infinite, Timeout.Infinite); // WILL NOT WORK!!!
当然,这只会产生编译错误
未赋值局部变量“t”的使用
在Timer
类中也没有State
setter或SetState
方法,因此在构造后无法设置状态
如何完全模拟完整框架的计时器(TimerCallback)
构造函数?请注意,只要在设置字段/属性后手动启动计时器,这些选项是可以接受的,这意味着在指定的时间内使用Timeout.Infinite
状态对象
将属性添加到状态对象:
public class MyState
{
public Timer { get; set; }
}
//create empty state
MyState s = new MyState();
//create timer paused
Timer t = new Timer(MyCallback, s, Timeout.Infinite, Timeout.Infinite);
//update state
s.Timer = t;
//now safe to start timer
t.Change(..)
私人领域
内部类的私有域
如果一个私有字段不够,因为您想启动并跟踪多个字段,那么创建一个新类来包装一个计时器。这可能是一个内部类:
public class ExistingClass
{
public void Launch()
{
new TimerWrapper(this);
}
private sealed class TimerWrapper
{
private readonly ExistingClass _outer;
private readonly Timer _t;
public TimerWrapper(ExistingClass outer)
{
_outer = outer;
//start timer
_t = new Timer(state=>_outer.MyCallBack(this),
null, Timeout.Infinite, Timeout.Infinite);
}
public Timer Timer
{
get { return _t; }
}
}
private void MyCallBack(TimerWrapper wrapper)
{
wrapper.Timer.
}
}
你可以使用闭包。例如:
Timer t = null;
t = new Timer(
_ =>
{
if (t != null)
{
// simply use t here, for example
var temp = t;
}
},
null,
Timeout.Infinite,
Timeout.Infinite);
注意我如何测试t!=null
,以防计时器在分配给变量t
之前已经调用回调,如果将0用作dueTime的值,则可能会发生这种情况。如果值为Timeout.Infinite,则不会发生这种情况,但我喜欢在多线程场景中进行防御
除了t
,您还可以在创建计时器时使用范围内的任何其他变量,因为它们都将被提升到闭包中(在回调中使用时)
如果您只需要一个方法来替换缺少的构造函数,从而简化移植工作,那么它就是:
public static Timer Create(TimerCallback callback)
{
Timer t = null;
t = new Timer(_ => callback(t), null, Timeout.Infinite, Timeout.Infinite);
return t;
}
due time参数中的Timeout.Infinite
可防止出现该问题。i、 e.在计时器被后面的一行代码启动之前,回调不会被调用。我以前也尝试过这个方法,它不允许您使用闭包中可能没有ben赋值的值-它不会编译。@weston我在发布后不久就注意到了这两个问题。答案已经更新。“但我喜欢在多线程场景中防御”,您的代码所做的只是隐藏一个潜在的空引用异常。防御性编程不是确保程序不会抛出异常。如果它有一个执行特殊操作的else
,或者抛出一个自定义异常,那就更好了。@weston我明白你的意思,但我不是这么想的。相反,我的想法是:如果回调的第一次迭代来得太早,只需什么都不做,等待第二次迭代。但是,正如您所看到的,当这个逻辑被很好地封装在一个方法中时,就不需要保护不可能发生的情况(因为Timeout.Infinite)。这个问题有点不对劲,Windows 8.1的相关性是什么。NET 4.5.1当然支持此构造函数。如果你真的在谈论一个商店应用程序,那么你根本不能使用这个类。计时器类在8.0中不存在,但它确实包含在8.1版本的Windows应用商店应用程序中。你只是在MSDN文档中看不到而已。@AndersGustafsson出于兴趣,你选择了哪个选项?承认这有点尴尬,但经过进一步调查,我发现移植代码的任何回调方法中都没有使用state
。因此,我简单地将计时器(回调)
构造函数替换为计时器(回调,null,Timeout.Infinite,Timeout.Infinite)
。@AndersGustafsson lol至少是其他人编写的原始代码?在我的辩护中:是的,它是:-)
public static Timer Create(TimerCallback callback)
{
Timer t = null;
t = new Timer(_ => callback(t), null, Timeout.Infinite, Timeout.Infinite);
return t;
}