简体   繁体   中英

What's the easiest way to have a timed callback in .NET?

I want to do something like this in C# (more specifically, WPF):

Thread.Invoke(MyCallback, 1000);

Which will just call MyCallback, 1 time, 1 second from now.

What is the easiest way to do this with .NET? Do I have to setup a Timer and hook an event?

You can use System.Timers.Timer to do this without spawning your own thread. Implement the Elapsed callback to do what you want, setting Enabled true and AutoReset false to achieve a single invocation.

Make sure you Dispose the Timer object once you are done with it!

Here's a method that runs an Action after a certain timeout using a Timer :

static void Invoke(TimeSpan dueTime, Action action)
{
    Timer timer = null;
    timer = new Timer(_ => { timer.Dispose(); action(); });
    timer.Change(dueTime, TimeSpan.FromMilliseconds(-1));
}

I'm not sure how lightweight exactly a Timer is, but it should be better than blocking a ThreadPool thread.

Usage:

Invoke(TimeSpan.FromSeconds(5), () =>
{
    Console.WriteLine("Hello World");
});
Task.Factory.StartNew(() =>
{
    Thread.Sleep(1000);
    // Do Stuff
});

As noted in comments below, although easy to understand and short to write, this is a relatively inefficient/resource hungry way of doing this.

Usage:

Delay.Invocation(MyCallback, 1000);

//or

Delay.Invocation(() => MyCallbackWithArgs(arg1, arg2), 1000);

Wrapper:

public class Delay
{
    readonly Timer _timer;
    readonly Action _action;

    private Delay(Action action, double delayMilliseconds)
    {
        _action = action;
        _timer = new Timer(delayMilliseconds);
        _timer.Elapsed += ExecuteCallback;
    }

    void ExecuteCallback(object sender, ElapsedEventArgs e)
    {
        _timer.Stop();
        _timer.Elapsed -= ExecuteCallback;
        _timer.Dispose();

        _action();
    }

    void Begin()
    {
        _timer.Start();
    }

    public static void Invocation(Action action, int delayMilliseconds)
    {
        var delay = new Delay(action, delayMilliseconds);
        delay.Begin();
    }
}

Just my 2 cents,

public class WaitableWorker
    {
        private readonly System.Threading.Timer timer;
        public WaitableWorker(int interval, Action callback, bool blocking = false)
        {
            if (blocking)
            {
                Thread.Sleep(interval);
                callback();
            }
            else
            {
                timer = new System.Threading.Timer(_ =>
                                                       {
                                                           timer.Dispose();
                                                           callback();
                                                       },
                                                   null, interval, Timeout.Infinite);
            }
        }

    }

Usage

 WaitableWorker worker=new WaitableWorker(3000,DoWork);

If you've got the Reactive Extensions , you can do this:

Observable.Return(true)
    .Delay(TimeSpan.FromSeconds(1))
    .Subscribe(_ => DoWork());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM