Вызов / вызов метода на основе строкового значения, содержащегося в массиве - PullRequest
3 голосов
/ 27 марта 2012

У меня есть struct-array, который содержит детали различных отчетов, которые можно запустить.Каждый отчет вызывает отдельный метод, и в настоящее время программа должна вручную проверить выбранное значение отчета, чтобы специально вызвать соответствующий метод.

Я хотел бы сохранить имя метода в массиве struct, а затем заставить программу вызывать этот метод при совпадении.Возможно ли это?

В настоящее время:

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

В идеале:

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

ОБНОВЛЕНИЕ

Я устал от рядапредложения ниже и ни один из них не сработал.Они не работали, вероятно, из-за того, как я структурировал мою программу.

Ответы [ 7 ]

6 голосов
/ 27 марта 2012

Вы можете сделать это, используя отражение , но IMO оно слишком хрупкое: оно вводит невидимую зависимость от имени вызываемого вами метода.

// 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});

Лучшим подходом было бы определить делегат на основе вашего метода и сохранить его в структуре / классе вместо имени метода.

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);
    }
}

Вместо определения собственных типов делегатов вы можете использовать предопределенные типы на основе Action<T1,T2,...> или Func<T1,T2,R>, в зависимости от необходимости возвращать значения из отчетов.

3 голосов
/ 27 марта 2012

Вместо сохранения имени метода вы можете сохранить делегата:

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();
}

Большинство людей предпочитают альтернативный синтаксис, в котором вы можете вызывать делегата, как если бы это был метод, используя список аргументов в скобках. Я склонен избегать этого, потому что может быть неоднозначно, является ли вызываемая вещь методом или делегатом:

MyArray[i].Method();

В этом случае мы вызываем делегат, на который ссылается свойство Method, но этот код также может представлять вызов метода с именем «Метод». Смешение.

2 голосов
/ 27 марта 2012

Если все методы имеют одну и ту же сигнатуру, одним из способов будет кэширование делегата:

// 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.
}
1 голос
/ 27 марта 2012

Что касается меня, то поддержка простого переключения намного проще, чем работа с отражением, массивом имен методов или делегатов и вызов этого материала:

switch (reportType)
{
    case "Daily_Unload":
        ReportDailyUnload();
        break;
    // ...
}
1 голос
/ 27 марта 2012

Добавьте свойство делегата в вашу структуру (например, типа Action), а затем просто вызовите этот делегат, когда вам это нужно.Просто установите это свойство для метода, который вы хотите вызвать при создании экземпляров структуры.

1 голос
/ 27 марта 2012

Да, вы говорите о отражении . Вот статья о том, как вызвать метод .Есть много вещей, которые вы можете найти на отражение с помощью Google.

0 голосов
/ 07 июня 2018

Использование delegate и dictionary<string, delegate>

void Main()
{
    var reports = new Dictionary<string, Report>
    {
        {"Daily_Unload", ReportDailyUnLoad}
    };

    var report = "Daily_Unload";
    reports[report]();
}

delegate string Report();

string ReportDailyUnLoad()
{
    return "daily unload report";
}
...