Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call/Invoke a method based on a string value contained in an array [duplicate]

I have a struct-array that contains details of different reports that can be run. Each report calls a different method and currently the program has to manually check the selected report value to specifically call the appropriate method.

I would like to store the method name in the struct-array and then have program invoke that method when there is match. Is this possible?

Currently:

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

Ideally:

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

UPDATE

I tired a number of the suggestions below and none of them worked. They didn't work probably due to how I have my program structured.

like image 394
John M Avatar asked Dec 04 '22 17:12

John M


2 Answers

You can do it using reflection, but IMO it is too fragile: it introduces an invisible dependency on the name of the method that you call.

// 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 the 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 pre-defined ones based on Action<T1,T2,...> or Func<T1,T2,R>, depending on your need to return values from the reports.

like image 154
Sergey Kalinichenko Avatar answered Dec 10 '22 10:12

Sergey Kalinichenko


Rather than storing the method name, you could store a 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 seem to prefer the alternative syntax where you can invoke a delegate as if it were a method, using a list of arguments in parentheses. I tend to avoid this, because it can be ambiguous whether the thing being invoked is a method or a delegate:

MyArray[i].Method();

In this case, we're invoking the delegate that is referred to by the Method property, but this code could also represent a call to a method called "Method". Confusing.

like image 21
phoog Avatar answered Dec 10 '22 10:12

phoog