Create a method call in .NET based on a string val

2020-02-11 00:09发布

Right now, I have code that looks something like this:

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

Is there any way to create code that would use my method naming conventions to simplify things? Here's some pseudocode that describes what I'm looking for:

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

12条回答
ゆ 、 Hurt°
2楼-- · 2020-02-11 00:39

You can, using System.Reflection. See this code project article for more information.

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);
                    }
                }
            }
        }
    }
}
查看更多
地球回转人心会变
3楼-- · 2020-02-11 00:41

The "Closest to your question" solution.

You could make delegates out of those reports, and call them by looking up the matching String in a 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

That way you can add as many reports as you like, and your ability to reflect them, and the perf hit of reflection, aren't an issue.

查看更多
戒情不戒烟
4楼-- · 2020-02-11 00:42

You can use reflection. Though personally, I think you should just stick with the switch statement.

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

Sorry, I'm doing C#. Just translate it to VB.NET.

查看更多
SAY GOODBYE
5楼-- · 2020-02-11 00:44

You could use reflection to do this but to be honest I think it's overcomplicating things for your particular scenario i.e. code and switch() in the same class.

Now, if you had designed the app to have each report type in its own assembly (kinda like an add-in/plugin architecture) or bundled in a single external assembly then you could load the reporting assemblie(s) into an appdomain and then use reflection to do this kinda thing.

查看更多
我只想做你的唯一
6楼-- · 2020-02-11 00:48

Use reflection. In the System.Reflection namespace you need to get a MethodInfo object for the method you want, using GetMethod("methodName") on the type containing the method.

Once you have the MethodInfo object, you can call .Invoke() with the object instance and any parameters.

For Example:

System.Reflection.MethodInfo method = this.GetType().GetMethod("foo");
method.Invoke(this, null);
查看更多
何必那么认真
7楼-- · 2020-02-11 00:49

Reflection API allows you to get a MethodInfo from a method, then calling Invoke dynamically on it. But it is overkill in your case.

You should consider having a dictionary of delegates indexed by strings.

查看更多
登录 后发表回答