5

I found a great way on how to do periodic work using the async/await pattern over here: https://stackoverflow.com/a/14297203/899260

Now what I'd like to do is to create an extension method so that I can do

someInstruction.DoPeriodic(TimeSpan.FromSeconds(5));

Is that possible at all, and if, how would you do it?

EDIT:

So far, I refactored the code from the URL above into an extension method, but I don't know how to proceed from there

  public static class ExtensionMethods {
    public static async Task<T> DoPeriodic<T>(this Task<T> task, CancellationToken token, TimeSpan dueTime, TimeSpan interval) {
        // Initial wait time before we begin the periodic loop.
        if (dueTime > TimeSpan.Zero)
            await Task.Delay(dueTime, token);

        // Repeat this loop until cancelled.
        while (!token.IsCancellationRequested) {


            // Wait to repeat again.
            if (interval > TimeSpan.Zero)
                await Task.Delay(interval, token);
        }
    }
}
Community
  • 1
  • 1
lightxx
  • 1,037
  • 2
  • 11
  • 29
  • Do you know how to create an extension method? If yes, you have the answer, if no, you can use Google. – Mohammad Dehghan Mar 18 '13 at 07:37
  • @MarcinJuraszek I've refactored the code from the link into an extension method, but I don't know how to proceed from there. See my edit. – lightxx Mar 18 '13 at 07:50

1 Answers1

4

Is the "periodic work" code accessing any of the someInstruction public members? If not, it does not make much sense to use an extension method in the first place.

if it does, and assuming that someInstruction is an instance of SomeClass, you could do something like the following:

public static class SomeClassExtensions
{
    public static async Task DoPeriodicWorkAsync(
                                       this SomeClass someInstruction,
                                       TimeSpan dueTime, 
                                       TimeSpan interval, 
                                       CancellationToken token)
    {
        //Create and return the task here
    }
}

Of course you must pass someInstruction to the Task constructor as a parameter (there is a constructor overload that allows you to do that).

UPDATE based on comment by OP:

If you just want to have a reusable method for executing arbitrary code periodically, then an extension method is not what you need, but rather a simple utility class. Adapting the code from the link you provided, it would be something like this:

public static class PeriodicRunner
{
public static async Task DoPeriodicWorkAsync(
                                Action workToPerform,
                                TimeSpan dueTime, 
                                TimeSpan interval, 
                                CancellationToken token)
{
  // Initial wait time before we begin the periodic loop.
  if(dueTime > TimeSpan.Zero)
    await Task.Delay(dueTime, token);

  // Repeat this loop until cancelled.
  while(!token.IsCancellationRequested)
  {
    workToPerform();

    // Wait to repeat again.
    if(interval > TimeSpan.Zero)
      await Task.Delay(interval, token);       
  }
}
}

Then you use it like this:

PeriodicRunner.DoPeriodicWorkAsync(MethodToRun, dueTime, interval, token);

void MethodToRun()
{
    //Code to run goes here
}

or with a simple lambda expression:

PeriodicRunner.DoPeriodicWorkAsync(() => { /*Put the code to run here */},
   dueTime, interval, token);
Konamiman
  • 49,681
  • 17
  • 108
  • 138
  • hm. my intention was like this: I'm reusing that code all over the place, and only the line with the comment "// TODO: Do some kind of work here. " changes. So i thought instead of copy and pasting that code all over the place, I would like to have some boilerplate code and just pass in the instructions. Hence the idea with the extension method. – lightxx Mar 18 '13 at 08:00
  • thanks!! btw "public static Task DoPeriodicWorkAsync" should be "public static async Task DoPeriodicWorkAsync" ;) – lightxx Mar 18 '13 at 08:24
  • Very useful answer bu I got an exception cancelling it: `TaskCanceledException` after using `Cancel()` method on the `CancellationTokenSource.token` I pass to the method. How to propely handle the cancellation of the `PeriodicRunner`? thanks – Rowandish Dec 12 '17 at 17:03