views:

1307

answers:

13

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
+3  A: 

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 it's 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.

Kev
A: 

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

Rick Minerich
+3  A: 

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.

EG:

System.Reflection.MethodInfo method = this.GetType().GetMethod("foo");
method.Invoke(this, null);
C. Lawrence Wenham
+7  A: 
Type type = GetType();
MethodInfo method = type.GetMethod("Show"+reportName+"Report");
if (method != null)
{
    method.Invoke(this, null);
}

This is C#, should be easy enough to turn it into VB. If you need to pass parameter into the method, they can be added in the 2nd argument to Invoke.

Chris Marasti-Georg
drive-by-down-voter: why? What's wrong with the solution?
Chris Marasti-Georg
No drive by, just observing that something here don't smell so good. See http://stackoverflow.com/questions/134214/create-a-method-call-in-net-based-on-a-string-value#134514. Why a String? Is it user input? Could the issue be avoided entirely? Should it be?
Dustman
A: 

You could do something like that with reflection, but I think you're code would be a lot uglier. How many of these would you have?

I think you'd be better off with some form of command-pattern where your enumerated strings are the command's name!

Ray Hayes
+3  A: 

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.

Romain Verdier
A: 

Python (and IronPython) can do this thing very easily. With .Net though, you need to use reflection.

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

My quick port to 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
torial
+2  A: 

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.

jop
A: 

If i understand the question correctly, you'll have to use Reflection to find the method "show" + reportName and then invoke it indirectly:

Half-baked example:

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

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

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

}

Insert your own logic there to make up the name for the method to call.

See MSDN documentation of MethodInfo and Assembly for details.

axel_c
A: 

Using reflection:

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

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

But I agree with ago, better not change your original code ;-)

Treb
+2  A: 

You've got a deeper problem. Your strings are too important. Who is passing you strings? can you make them not do that?

Stick with the switch statement, as it decouples your internal implementation (method names) from your external view.

Suppose you localize this to German. You gonna rename all those methods?

Jay Bazuzi
A: 

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.

Dustman
A: 

Reflection would be an ok solution if the number of methods exceeds at least 20..30.

Andrei Rinea