2008-09-25 9 views
9

En este momento, no tengo código que se ve algo como esto:Crear una llamada a un método en .NET basado en un valor de cadena

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 

¿Hay alguna manera de crear un código que utilizaría mis convenciones de nombres de método para simplificar ¿cosas? Aquí hay algo de pseudocódigo que describe lo que estoy buscando:

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

¿Estás seguro de que no sería más fácil volver a escribir lo que está llamando a tu función con una cadena? – GEOCHET

+0

Muy cierto. Creo que estamos buscando buenas formas de construir algo que sea, bueno, no tan bueno. – Dustman

+0

No estoy seguro de lo que quiere decir al reescribir algo con una cadena. – Jim

Respuesta

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

Esto es C#, debe ser lo suficientemente fácil de convertirlo en VB. Si necesita pasar un parámetro al método, se pueden agregar en el segundo argumento a Invocar.

+3

votante de paso a paso: ¿por qué? ¿Qué pasa con la solución? –

+1

No conduzca, solo observe que algo aquí no huele tan bien. Consulte http://stackoverflow.com/questions/134214/create-a-method-call-in-net-based-on-a-string-value#134514. ¿Por qué una cadena? ¿Es la entrada del usuario? ¿Se podría evitar el problema por completo? ¿Deberia ser? – Dustman

3

Se podría utilizar la reflexión para hacer esto, pero para ser honesto, creo que complicar las cosas para su escenario particular, es decir, el código y el interruptor() en la misma clase.

Ahora, si ha diseñado la aplicación para tener cada tipo de informe en su propio conjunto (como una arquitectura de complementos/complementos) o en un único ensamblaje externo, puede cargar los ensamblados de informes en un dominio de aplicación y luego usa la reflexión para hacer esto.

0

Puede usar System.Reflection. Consulte this code project article para obtener más información.

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

Use la reflexión. En el espacio de nombre System.Reflection necesita obtener un objeto MethodInfo para el método que desee, utilizando GetMethod("methodName") en el tipo que contiene el método.

Una vez que tenga el objeto MethodInfo, puede llamar al .Invoke() con la instancia del objeto y los parámetros.

Por ejemplo:

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

Reflection API le permite obtener un MethodInfo de un método, y luego llamar al Invoke de forma dinámica. Pero es excesivo en tu caso.

Debería considerar tener un diccionario de delegados indexado por cadenas.

+0

mente mostrando un ejemplo de cómo lograr un diccionario de delegados indexados por cadenas y llamar a los métodos? – SSpoke

0

Python (y IronPython) pueden hacer esto con mucha facilidad. Sin embargo, con .Net, necesitas usar la reflexión.

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

mi puerto rápida a 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 
2

Puede utilizar la reflexión. Aunque personalmente, creo que deberías seguir con la declaración de cambio.

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

Lo siento, estoy haciendo C#. Simplemente tradúzcalo a VB.NET.

+0

Si el método devuelve algo, ¿se almacenará? – siri

+0

Invocar devuelve un objeto. Simplemente transfiéralo al tipo apropiado. – jop

0

si entiendo la pregunta correctamente, usted tiene que utilizar la reflexión para encontrar el método "mostrar" + reportName y luego invocar de forma indirecta: ejemplo

a medias:

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

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

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

} 

Insertar su propia lógica allí para inventar el nombre del método para llamar.

Consulte la documentación de MSDN sobre MethodInfo y Assembly para obtener más información.

0

El uso de la reflexión:

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

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

Pero estoy de acuerdo con la hace, mejor no cambiar su código original ;-)

4

Tienes un problema más profundo. Tus cadenas son muy importantes. ¿Quién te está pasando cadenas? puedes hacer que ellos no hagan eso?

Manténgase en la instrucción switch, ya que desacopla su implementación interna (nombres de métodos) de su vista externa.

Supongamos que localizas esto en alemán. ¿Cambiarás el nombre de todos esos métodos?

0

La solución "Más cercana a su pregunta".

Se podría hacer que los delegados de esos informes, y llamarlos por buscar la cadena coincidente en una tabla hash:

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 

esa manera usted puede añadir tantos informes como desee, y su capacidad para reflejar ellos, y el impacto de la reflexión, no son un problema.

Cuestiones relacionadas