Question

I am writing a class which utilizes a USING statement to connect to the task scheduler on a server and "does things"; like enable/disable a task, start and stop etc. I want to improve code reuse, perhaps by using delegates, but I'm not sure how to go about it. Here's some of my current code:

private static void StopRunningTask(string taskName, string hostName)
{
   Regex regex = GetRegexForFindTask(taskName);
   using (TaskService ts = new TaskService(hostName))
   {
      foreach (Task t in ts.FindAllTasks(regex, true))
      {
         if (t.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase) && t.State == TaskState.Running)
           t.Stop();
      }
   }

private static void RunTask(string taskName, string hostName)
{
   Regex regex = GetRegexForFindTask(taskName);
   using (TaskService ts = new TaskService(hostName))
   {
      foreach (Task t in ts.FindAllTasks(regex, true))
      {          
         if (t.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase) && t.State == TaskState.Ready)
         t.Run();
      }
   }

private static void ChangeTaskEnabledState(string taskName, bool enabled, string hostName)
{
   Regex regex = GetRegexForFindTask(taskName);
   using (TaskService ts = new TaskService(hostName))
   {
      foreach (Task t in ts.FindAllTasks(regex, true))
      {
         if (t.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase))
         t.Enabled = enabled;
      }
   }

private static Regex GetRegexForFindTask(string taskName)
{
   var regex = new Regex(string.Format(@"{0}", taskName), RegexOptions.IgnoreCase);
   return regex;
}
Was it helpful?

Solution

You can just provide a callback instead for the method - e.g.

private static void FindTasks(string taskName, string hostName, Action<Task> callback)
{
    Regex regex = GetRegexForFindTask(taskName);

    using (TaskService ts = new TaskService(hostName))
    {
        foreach (Task t in ts.FindAllTasks(regex, true))
            if (t.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase))
                callback(t);
    }
}

Then to call:

FindTask("SomeTaskName", "SomeHost", (task) => t.Enabled = true);

Obviously though your FindTask implementation looks like it differs slightly (you check for IsEnabled in some cases etc) so you could use something like this where you do that check in the anonymous delegate:

FindTask("SomeTaskName", "SomeHost", (task) => 
    { 
        // Check if it is running first
        if(t.IsRunning) t.Enabled = false; 
    });

Or you could pass a predicate to the FindTask method to filter the list - let me just dig up the syntax..

Edit: would be something like:

public static void FindTask(string taskName, string hostName, Expression<Func<T, bool>> filter, Action<Task> callback)
{
    Regex regex = GetRegexForFindTask(taskName);

    using (TaskService ts = new TaskService(hostName))
    {
        foreach (Task t in ts.FindAllTasks(regex, true).Where(filter)) // Use linq filter here to narrow down the list of tasks
            if (t.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase))
                callback(t);
    }
}

And to use:

FindTask("SomeTaskName", "SomeHost", task => task.IsEnabled, (task) => task.IsEnabled = false);

So it would only run the callback on IsEnabled tasks

Obviously then you have to wonder what you can put into the predicate! The balance is yours to determine :)

The only thing you need to think about though, is that allowing another user (3rd party maybe) to use this allows them to do whatever they want to the task since they get an instance of the task back to operate on. At least with your original implementation, you are constrained to just the operations you specify. (This may not be a problem for you though if it's just for your own use/internal use)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top