djangojazz
djangojazz

Reputation: 13232

Passing in a Task to to make a method more generic for reuse does not behave as expected asynchronously

So essentially I want to pass in an Action or Function Lambda statement to a method to reuse a generic timer functionality with different methods. So I could do something like GenericTimer(1000, Task1DoesThisThing) and GenericTimer(3000, Task2DoesThisCompletelyOtherThing). I just want reusability and do not care if a different method is given to me drastically different than what I am doing.

private static void TimerGeneric(int duration, Task timerDuration)
{
  var timer = new Timer(duration);
  timer.Elapsed += async (sender, e) => await timerDuration;
  timer.Enabled = true;
}

private static void TimerSetupWithRefresh(int refreshDuration)
{
  Timer timer = new Timer(refreshDuration);
  timer.Elapsed += async (sender, e) => await Refresh();
  timer.Enabled = true;
}

private static async Task Refresh()
{
  Console.WriteLine("Specific is: " + DateTime.Now);
}

public class Poc { public int Id { get; set; } public string Value { get; set; }}

static void Main(string[] args)
{
  //Works just as expected and refreshes every second for the 'Refresh()' method.
  TimerSetupWithRefresh(1000);

  //Below does not work yet I would expect a Task passed in via signature with near same method would behave the same.
  TimerGeneric(1000, new Task(() => { Console.WriteLine("Passed in Task is: " + DateTime.Now); }));

  Console.ReadLine();
}

Upvotes: 0

Views: 336

Answers (1)

Lukazoid
Lukazoid

Reputation: 19416

Currently you are passing in a Task which is never started. I think what you actually want is to take a delegate which invokes an asynchronous method, this can be done using a parameter of type Func<Task> like so:

private static void TimerGeneric(int duration, Func<Task> timerDuration)
{
    var timer = new Timer(duration);
    timer.Elapsed += async (sender, e) => await timerDuration();
    timer.Enabled = true;
}

Then use it like so:

TimerGeneric(1000, async () => { Console.WriteLine("Passed in Task is: " + DateTime.Now); });

Although it would be preferential for the async method to actually perform some asynchronous work, or failing that simply return a completed Task:

TimerGeneric(1000, () => 
    { 
        Console.WriteLine("Passed in Task is: " + DateTime.Now);
        return Task.CompletedTask;
    });

This can be preferential as it eliminates the underlying asynchronous state machine which is unnecessary for a synchronous implementation.

Upvotes: 1

Related Questions