Создать вызов метода в .NET на основе строкового значения

Сейчас у меня есть код, который выглядит примерно так:

Private Sub ShowReport(ByVal reportName As String)
    Select Case reportName
        Case "Security"
            Me.ShowSecurityReport()
        Case "Configuration"
            Me.ShowConfigurationReport()
        Case "RoleUsers"
            Me.ShowRoleUsersReport()
        Case Else
            pnlMessage.Visible = True
            litMessage.Text = "The report name """ + reportName + """ is invalid."
    End Select
End Sub

Есть ли способ создать код, который будет использовать соглашения об именах методов для упрощения? Здесь некоторый псевдокод, который описывает то, что я ищу:

Private Sub ShowReport(ByVal reportName As String)
    Try
        Call("Show" + reportName + "Report")
    Catch ex As Exception
        'method not found
    End Try
End Sub

Ответ 1

Type type = GetType();
MethodInfo method = type.GetMethod("Show"+reportName+"Report");
if (method != null)
{
    method.Invoke(this, null);
}

Это С#, должно быть достаточно легко превратить его в VB. Если вам нужно передать параметр в метод, они могут быть добавлены во втором аргументе для вызова.

Ответ 2

У вас есть более глубокая проблема. Ваши строки слишком важны. Кто передает вам строки? можете ли вы заставить их этого не делать?

Придерживайтесь оператора switch, поскольку он отделяет вашу внутреннюю реализацию (имена методов) от внешнего вида.

Предположим, вы локализуете это на немецком языке. Вы переименуете все эти методы?

Ответ 3

Вы можете использовать отражение, чтобы сделать это, но, честно говоря, я считаю, что это слишком сложно для вашего конкретного сценария, то есть кода и switch() в том же классе.

Теперь, если вы разработали приложение для каждого типа отчета в своей собственной сборке (вроде архитектуры надстройки/плагина) или в комплекте с одной внешней сборкой, вы можете загрузить сборку отчетности в appdomain, а затем использовать рефлексию, чтобы сделать эту вещь.

Ответ 4

Используйте отражение. В пространстве имен System.Reflection вам нужно получить объект MethodInfo для метода, который вы хотите, используя GetMethod("methodName") для типа, содержащего метод.

Как только у вас есть объект MethodInfo, вы можете вызвать .Invoke() с экземпляром объекта и любыми параметрами.

Пример:

System.Reflection.MethodInfo method = this.GetType().GetMethod("foo");
method.Invoke(this, null);

Ответ 5

API Reflection позволяет вам получить MethodInfo из метода, а затем динамически называть Invoke. Но в вашем случае это слишком много.

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

Ответ 6

Вы можете использовать отражение. Хотя лично, я думаю, вы должны просто придерживаться инструкции switch.

private void ShowReport(string methodName)
{
    Type type = this.GetType();
    MethodInfo method = type.GetMethod("Show"+methodName+"Report", BindingFlags.Public)
    method.Invoke(this, null);
}

Извините, я делаю С#. Просто переведите его на VB.NET.

Ответ 7

Вы можете, используя System.Reflection. Смотрите эту статью проекта кода для получения дополнительной информации.

string ModuleName = "TestAssembly.dll";
string TypeName = "TestClass";
string MethodName = "TestMethod";

Assembly myAssembly = Assembly.LoadFrom(ModuleName);

BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | 
  BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);

Module [] myModules = myAssembly.GetModules();
foreach (Module Mo in myModules) 
{
 if (Mo.Name == ModuleName) 
     {
     Type[] myTypes = Mo.GetTypes();
     foreach (Type Ty in myTypes)
         {
        if (Ty.Name == TypeName) 
            {
            MethodInfo[] myMethodInfo = Ty.GetMethods(flags);
            foreach(MethodInfo Mi in myMethodInfo)
                {
                if (Mi.Name == MethodName) 
                    {
                    Object obj = Activator.CreateInstance(Ty);
                    Object response = Mi.Invoke(obj, null);
                    }
                }
            }
        }
    }
}

Ответ 8

Python (и IronPython) может сделать это очень легко. С .Net, однако, вам нужно использовать отражение.

В С#: http://www.dotnetspider.com/resources/4634-Invoke-me-ods-dynamically-using-reflection.aspx

Мой быстрый порт для VB.Net:

Private Sub InvokeMethod(instance as object, methodName as string )
            'Getting the method information using the method info class
            Dim mi as MethodInfo = instance.GetType().GetMethod(methodName)

            'invoing the method
            'null- no parameter for the function [or] we can pass the array of parameters
            mi.Invoke(instance, Nothing)
End Sub

Ответ 9

Если я правильно понял вопрос, вам нужно будет использовать Reflection, чтобы найти метод "показать" + имя_отчета, а затем косвенно коснуться его:

Пример с половинным испечением:

Case "financial" :
{
   Assembly asm = Assembly.GetExecutingAssembly ();

    MethodInfo mi = asm.GetType ("thisClassType").GetMethod ("showFinancialReport");

   if (mi != null)
      mi.Invoke (null, new object[] {});

}

Вставьте свою собственную логику, чтобы составить имя для вызова метода.

Подробнее см. документацию MSDN для MethodInfo и Assembly.

Ответ 10

Использование отражения:

Type t = this.GetType();
try 
{
    MethodInfo mi = t.GetMethod(methodName, ...);

    if (mi != null)
    {
        mi.Invoke(this, parameters);
    }
} 

Но я согласен с тем, что лучше не менять исходный код; -)

Ответ 11

Решение "Ближайшие к вашему вопросу".

Вы можете сделать делегатов из этих отчетов и вызвать их, посмотрев соответствующую строку в Hashtable:

Public Sub New()
    '...
    ReportTable.Add("Security", New ReportDelegate(AddressOf ShowSecurityReport))
    ReportTable.Add("Config", New ReportDelegate(AddressOf ShowConfigReport))
    ReportTable.Add("RoleUsers", New ReportDelegate(AddressOf ShowRoleUsersReport))
    '...
End Sub

Private Sub ShowSecurityReport()
    '...
End Sub

Private Sub ShowConfigReport()
    '...
End Sub

Private Sub ShowRoleUsersReport()
    '...
End Sub

Private Delegate Sub ReportDelegate()

Private ReportTable As New Dictionary(Of String, ReportDelegate)

Private Sub ShowReport(ByVal reportName As String)
    Dim ReportToRun As ReportDelegate
    If ReportTable.TryGetValue(reportName, ReportToRun) Then
        ReportToRun()
    Else
        pnlMessage.Visible = True
        litMessage.Text = "The report name """ + reportName + """ is invalid."
    End If
End Sub

Таким образом, вы можете добавить столько отчетов, сколько хотите, и ваша способность отражать их, а также перфоманс отражения - это не проблема.

Ответ 12

Работал для меня в VB.Net MSVS 2015

Dim tip As Type = GetType(MODULENAME)'if sub() or funcion() in module
        Dim method As MethodInfo = tip.GetMethod("MaxV") 'name of function (gets 2 params double type)
        Dim res As Double = 0 'temporary variable
        If (Not Nothing = method) Then 'if found function "MaxV"

            res = method.Invoke(Me, New Object() {10, 20})
        End If
        MsgBox(res.ToString())