Timer in Windows 8.1 - how to simulate a Timer constructor (TimerCallback)?

I am migrating an existing .NET class library that uses System.Threading.Timer in a Windows Store app designed for Windows 8.1. The Timer class is available, but several parameters seem to be missing with respect to the corresponding .NET Framework Timer .

In particular, only two constructors are available in the Windows Store version:

 public Timer(TimerCallback callback, Object state, int dueTime, int period); public Timer(TimerCallback callback, Object state, TimeSpan dueTime, TimeSpan period); 

The .NET Framework contains this additional constructor:

 public Timer(TimerCallback callback); 

which according to the MSDN documentation sets dueTime and period to Timeout.Infinite and state to a Timer object by itself.

Trying to replace the constructor of single arguments, I "naively" tried to pass the Timer object to one of the Windows 8.1 constructors, for example:

 Timer t; t = new Timer(MyCallback, t, Timeout.Infinite, Timeout.Infinite); // WILL NOT WORK!!! 

but of course this only leads to a compilation error

Using the unassigned local variable 't'

There is also no state setter or SetState method in the Timer class, so state cannot be set after construction.

What can I do to completely imitate the constructor of the complete Timer(TimerCallback) structure Timer(TimerCallback) ?

+1
source share
2 answers

Please note that these parameters are acceptable if you start the timer manually after setting the field / property, which means that you use Timeout.Infinite for your time.

State object

Add a property to the state object:

 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(..) 

Private field

 _t = new Timer(MyCallback, null, Timeout.Infinite, Timeout.Infinite); MyCallback(object state) { // now have access to the timer _t _t. } 

Private Field Inner Class

And if one private field is not enough, because you want to run and track several, create a new class that wraps the timer. This may be an inner class:

 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. } } 
+1
source

You can use closure. For instance:

 Timer t = null; t = new Timer( _ => { if (t != null) { // simply use t here, for example var temp = t; } }, null, Timeout.Infinite, Timeout.Infinite); 

Notice how I test t != null , in case the timer already calls a callback before it has been assigned to t , which can happen if you have to use 0 as the value for dueTime. With a Timeout.Infinite value, this cannot happen, but I like to defend myself in multi-threaded scripts.

In addition to t you can use any other variable that is in scope when creating a timer, since they will all be raised in closure (when used in a callback).

If you only need a way to replace the missing constructor, making it easier to move it, here it is:

 public static Timer Create(TimerCallback callback) { Timer t = null; t = new Timer(_ => callback(t), null, Timeout.Infinite, Timeout.Infinite); return t; } 
+1
source

Source: https://habr.com/ru/post/957116/


All Articles