How to determine the original name of a function passed as a delegate

64 views Asked by At

I want to make a scheduler that runs every 5 minutes, and keeps track of functions that need only be executed once a day. I want to store the last runtime of each job in a (static) dictionary 'LastRuntimePerJob'.

I have created a delegate and a function that only executes the job when it has not been run today.

The code below does not work since nameof(jobToPerform) returns jobToPerform. How can I get the actual name of the function (Job1) from the delegate jobToPerform?

using System;
using System.Collections.Generic;
namespace Euler.Business.Problem.Progress
{
    public class Scheduler
    {
        public delegate void JobToPerform();
        public void Job1()
        {
            // Perform some task
        }

        public static Dictionary<string, DateTime> LastRuntimePerJob { get; set; } = new Dictionary<string, DateTime>();

        public void RunScheduler()
        {
            ExecuteWhenNecessary(Job1);
        }

        public void ExecuteWhenNecessary(JobToPerform jobToPerform)
        {
            var nameOfCurrentJob = nameof(jobToPerform);

            if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
            || LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
            {
                jobToPerform();
                if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
                {
                    LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
                }
                else
                {
                    LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
                }
            }
        }
    }
}
1

There are 1 answers

2
ale91 On BEST ANSWER

nameof is used to get the literal name of variables, type or member and it is executed at compile time (no effect at runtime). I think that you should use jobToPerform.Method.Name to retreive the delegate real method name, so check and try the following code and let me know!

using System;
using System.Collections.Generic;
namespace Euler.Business.Problem.Progress
{
    public class Scheduler
    {
        public delegate void JobToPerform();
        public void Job1()
        {
            // Perform some task
        }

        public static Dictionary<string, DateTime> LastRuntimePerJob { get; set; } = new Dictionary<string, DateTime>();

        public void RunScheduler()
        {
            ExecuteWhenNecessary(Job1);
        }

        public void ExecuteWhenNecessary(JobToPerform jobToPerform)
        {
            //var nameOfCurrentJob = nameof(jobToPerform);
            var nameOfCurrentJob = jobToPerform.Method.Name;  //Returns delegate method name

            if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
            || LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
            {
                jobToPerform();
                if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
                {
                    LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
                }
                else
                {
                    LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
                }
            }
        }
    }
}

EDIT - Note: if the delegate is anonymous you retreive the runtime assigned name:

public void RunScheduler()
{
   ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); });
}

the method name will be like: <RunScheduler>b__6_0.

You can modify the ExecuteWhenNecessary method signature to specify the method name you want to use as Dictionary Key:

public void ExecuteWhenNecessary(JobToPerform jobToPerform, , string nameOfCurrentJob = null)
{
   if (string.IsNullOrWhiteSpace(nameOfCurrentJob))
   {
      nameOfCurrentJob = jobToPerform.Method.Name;
   }

   if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
        || LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
   {
      jobToPerform();
      if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
      {
         LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
      }
      else
      {
         LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
      }
   }
}

And call method like:

ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); }, "MyMethodName");  //Anonymous
ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); }, nameof(Job1));