Call / Call a method based on a string value contained in an array

I have a structured array containing the details of various reports that can be run. Each report calls a different method, and currently the program needs to manually check the selected report value in order to specifically call the appropriate method.

I would like to store the name of the method in a struct array and then the program is called by that method when there is a match. Is it possible?

Currently

if (this.cboSelectReport.Text == "Daily_Unload")
{
   reportDailyUnload();
 }

      

Perfectly:

if(this.cboSelectReport.Text == MyArray[i].Name)
{
   something(MyArray[i].MethodName);
}

      

UPDATE

I got tired of a number of suggestions below and none of them worked. They didn't work, probably because of the way I am structured in my program.

+3


source to share


6 answers


You can do it with reflection, but IMO is too fragile: it introduces an invisible dependency on the name of the method you are calling.

// Assuming that the method is static, you can access it like this:
var namedReportMethod = "MyReport1";
var reportMethod = typeof(ReporterClass).GetMethod(namedReportMethod);
var res = reportMethod.Invoke(null, new object[] {reportArg1, reportArg2});

      

A better approach would be to define a delegate based on your method and store it in a struct / class instead of the method name.



delegate void ReportDelegate(int param1, string param2);

class Runner {
    public static void RunReport(ReportDelegate rd) {
        rd(1, "hello");
    }
}

class Test {
    static void TestReport(int a, string b) {
        // ....
    }
    public static void Main(string[] args) {
        Runner.RunReport(TestReport);
    }
}

      

Instead of defining your own delegate types, you can use predefined based on Action<T1,T2,...>

or Func<T1,T2,R>

, depending on your need, return values ​​from reports.

+6


source


Instead of storing the method name, you can store the delegate:

struct ReportInfo
{
    public string Name { get; set; }
    public Action Method { get; set; }
}

//...

MyArray[0] = new ReportInfo { Name = "Daily_Unload", Action = this.reportDailyUnload };

//...

if(this.cboSelectReport.Text == MyArray[i].Name)
{
    MyArray[i].Method.Invoke();
}

      

Most people prefer an alternative syntax in which you can invoke the delegate as if it were a method using a parenthesized list of arguments. I try to avoid this because it can be ambiguous if the thing called is a method or a delegate:



MyArray[i].Method();

      

In this case, we are calling the delegate that the property refers to Method

, but this code can also be a method call. Mixing.

+3


source


If all methods use the same signature, one way is to cache the delegate:

// initialize, maybe in a constructor
Dictionary<string, Action> nameDelegateMapping = new Dictionary<string, Action>();
// setup the delegates
nameDelegateMapping.Add("Daily_Unload", reportDailyUnload);
// ... add more methods here.

// later
string methodName = this.cboSelectReport.Text;
Action action;
if (nameDelegateMapping.TryGetValue(methodName, out action))
{
  action();
}
else
{
  // tell user the method does not exist.
}

      

+2


source


Yes, what you are talking about is reflection . Here is an article on how to call a method . You can find the reflection on Google.

+1


source


Add a delegate property to your structure (like an Action type) and then just call that delegate when you need it. Just set this property to the method you want to call when instantiating the structure.

+1


source


As for me, maintaining a simple switch is much easier than working with reflection, an array of method or delegate names and calling this stuff:

switch (reportType)
{
    case "Daily_Unload":
        ReportDailyUnload();
        break;
    // ...
}

      

+1


source







All Articles