Pase el método como parámetro usando C #

Tengo varios métodos, todos con la misma firma (parámetros y valores de retorno), pero los diferentes nombres y las partes internas de los métodos son diferentes. Quiero pasar el nombre del método para ejecutarlo a otro método que invocará el método aprobado.

public int Method1(string) { ... do something return myInt; } public int Method2(string) { ... do something different return myInt; } public bool RunTheMethod([Method Name passed in here] myMethodName) { ... do stuff int i = myMethodName("My String"); ... do more stuff return true; } public bool Test() { return RunTheMethod(Method1); } 

Este código no funciona, pero esto es lo que bash hacer. Lo que no entiendo es cómo escribir el código RunTheMethod ya que necesito definir el parámetro.

Puede usar el delegado Func en .net 3.5 como el parámetro en su método RunTheMethod. El delegado de Func le permite especificar un método que toma una cantidad de parámetros de un tipo específico y devuelve un único argumento de un tipo específico. Aquí hay un ejemplo que debería funcionar:

 public class Class1 { public int Method1(string input) { //... do something return 0; } public int Method2(string input) { //... do something different return 1; } public bool RunTheMethod(Func myMethodName) { //... do stuff int i = myMethodName("My String"); //... do more stuff return true; } public bool Test() { return RunTheMethod(Method1); } } 

Necesitas usar un delegado . En este caso, todos sus métodos toman un parámetro de string y devuelven un int ; esto se representa más simplemente por Func delegate 1 . Entonces su código puede volverse correcto con un cambio tan simple como este:

 public bool RunTheMethod(Func myMethodName) { // ... do stuff int i = myMethodName("My String"); // ... do more stuff return true; } 

Los delegates tienen mucho más poder que esto, en verdad. Por ejemplo, con C # puedes crear un delegado a partir de una expresión lambda , para que puedas invocar tu método de esta manera:

 RunTheMethod(x => x.Length); 

Eso creará una función anónima como esta:

 // The <> in the name make it "unspeakable" - you can't refer to this method directly // in your own code. private static int <>_HiddenMethod_<>(string x) { return x.Length; } 

y luego pasar ese delegado al método RunTheMethod .

Puede usar delegates para suscripciones de eventos, ejecución asincrónica, devoluciones de llamadas, todo tipo de cosas. Vale la pena leerlos, especialmente si quieres usar LINQ. Tengo un artículo que trata principalmente sobre las diferencias entre los delegates y los eventos, pero puede ser útil de todos modos.


1 Esto solo se basa en el tipo de delegado genérico Func en el marco; usted podría declarar fácilmente el suyo:

 public delegate int MyDelegateType(string value) 

y luego haga que el parámetro sea de tipo MyDelegateType en MyDelegateType lugar.

¡También puedes probar Acción delegada!

  public static int Method1(string mystring) { return 1; } public static int Method2(string mystring) { return 2; } public bool RunTheMethod(Action myMethodName) { myMethodName(); return true; } 

Y luego llama a tu método usando

 RunTheMethod(() => Method1("MyString1")); 

O

 public static object InvokeMethod(Delegate method, params object[] args) { return method.DynamicInvoke(args); } 

Entonces simplemente llame al método

 Console.WriteLine(InvokeMethod(new Func(Method1), "MyString1")); Console.WriteLine(InvokeMethod(new Func(Method2), "MyString2")); 
 public static T Runner(Func funcToRun) { //Do stuff before running function as normal return funcToRun(); } 

Uso:

 var ReturnValue = Runner(() => GetUser(99)); 

Debería usar un delegado Func , que representa una función que toma una string como argumento y devuelve un int :

 public bool RunTheMethod(Func myMethod) { // do stuff myMethod.Invoke("My String"); // do stuff return true; } 

Entonces úsalo:

 public bool Test() { return RunTheMethod(Method1); } 

Si desea la capacidad de cambiar qué método se llama en tiempo de ejecución, le recomendaría usar un delegado: http://www.codeproject.com/KB/cs/delegates_step1.aspx

Te permitirá crear un objeto para almacenar el método para llamar y puedes pasarlo a tus otros métodos cuando sea necesario.

Si bien la respuesta aceptada es absolutamente correcta, me gustaría proporcionar un método adicional.

Terminé aquí después de hacer mi propia búsqueda de una solución a una pregunta similar. Estoy construyendo un marco impulsado por un complemento, y como parte de él, quería que las personas pudieran agregar elementos de menú al menú de aplicaciones a una lista genérica sin exponer un objeto de Menu real porque el marco puede implementarse en otras plataformas que no tienen Objetos de la IU de Menu . Agregar información general sobre el menú es bastante fácil, pero permitir que el desarrollador del complemento tenga suficiente libertad para crear la callback cuando se hace clic en el menú resultó ser un problema. Hasta que caí en la cuenta de que estaba tratando de reinventar la rueda y llamar a los menús normales y activar la callback de los eventos.

Entonces la solución, tan simple como suena una vez que te das cuenta, me eludió hasta ahora.

Simplemente cree clases separadas para cada uno de sus métodos actuales, heredados de una base si es necesario, y simplemente agregue un controlador de eventos a cada uno.

Aquí hay un ejemplo que puede ayudarlo a comprender mejor cómo pasar una función como parámetro.

Supongamos que tiene la página principal y desea abrir una ventana emergente secundaria. En la página principal hay un cuadro de texto que debe rellenarse basándose en el cuadro de texto emergente de elementos secundarios.

Aquí necesitas crear un delegado.

Parent.cs // statement de delegado delegado público void FillName (String FirstName);

Ahora crea una función que llene tu cuadro de texto y la función debe asignar delegates

 //parameters public void Getname(String ThisName) { txtname.Text=ThisName; } 

Ahora, al hacer clic en el botón, debe abrir una ventana emergente secundaria.

  private void button1_Click(object sender, RoutedEventArgs e) { ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor p.Show(); } 

En el constructor ChildPopUp necesitas crear el parámetro de ‘tipo de delegado’ de la página principal //

ChildPopUp.cs

  public Parent.FillName obj; public PopUp(Parent.FillName objTMP)//parameter as deligate type { obj = objTMP; InitializeComponent(); } private void OKButton_Click(object sender, RoutedEventArgs e) { obj(txtFirstName.Text); // Getname() function will call automatically here this.DialogResult = true; } 

Para compartir una solución lo más completa posible, voy a terminar presentando tres formas diferentes de hacer, pero ahora voy a comenzar desde el principio más básico.


Breve introducción

Todos los lenguajes CLR ( Common Language Runtime ) (como C # y Visual Basic) funcionan bajo una VM llamada CLI ( Common Language Interpreter ) que ejecuta el código en un nivel más alto que los lenguajes nativos como C y C ++ (que comstackn directamente a código máquina) . Se deduce que los métodos no son ningún tipo de bloque comstackdo, sino que son solo elementos estructurados que CLR reconoce y usa para extraer su cuerpo y rebobinarlo siguiendo las instrucciones en línea del código máquina. Por lo tanto, no se puede pensar en pasar un método como parámetro, porque un método no produce ningún valor en sí mismo: ¡no es una expresión válida! Entonces, vas a tropezar con el concepto de delegado.


¿Qué es un delegado?

Un delegado representa un puntero a un método. Debido a que (como dije antes) un método no es un valor, hay una clase especial en los idiomas de CLR: Delegate . Esa clase ajusta cualquier método y puedes lanzar implícitamente cualquier método a eso.

Mira el siguiente ejemplo de uso:

 static void MyMethod() { Console.WriteLine("I was called by the Delegate special class!"); } static void CallAnyMethod(Delegate yourMethod) { yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ }); } static void Main() { CallAnyMethod(MyMethod); } 

Las tres formas:

  • Camino 1
    Use la clase especial Delegate directamente como el ejemplo anterior. El problema de esta solución es que su código se desmarcará a medida que pase dinámicamente sus argumentos sin restringirlos a los tipos de aquellos en la statement del método.

  • Forma 2/3 Además de la clase especial Delegate , el concepto de delegates se extiende a los delegates personalizados, que son declaraciones de los métodos precedidos por la palabra clave del delegate y se comportan como un método normal. Están tan controlados, y obtendrás un código ” perfecto “.

Mira el siguiente ejemplo:

 delegate void PrintDelegate(string prompt); static void PrintSomewhere(PrintDelegate print, string prompt) { print(prompt); } static void PrintOnConsole(string prompt) { Console.WriteLine(prompt); } static void PrintOnScreen(string prompt) { MessageBox.Show(prompt); } static void Main() { PrintSomewhere(PrintOnConsole, "Press a key to get a message"); Console.Read(); PrintSomewhere(PrintOnScreen, "Hello world"); } 

Una segunda opción de este modo para no escribir su propio delegado personalizado es usar uno de ellos declarado dentro de las bibliotecas del sistema:

  • Action envuelve un void sin argumentos.
  • Action envuelve un void con un argumento.
  • Action ajusta un void con dos argumentos.
  • Y así…
  • Func

    ajusta una función con el tipo de retorno TR y sin argumentos.

  • Func ajusta una función con el tipo de retorno TR y con un argumento.
  • Func ajusta una función con el tipo de retorno TR y con dos argumentos.
  • Y así…

(Esta última solución es que muchas personas publicaron).

Aquí hay un ejemplo sin un parámetro: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

con params: http://www.daniweb.com/forums/thread98148.html#

Básicamente pasas una serie de objetos junto con el nombre del método. luego usa ambos con el método Invoke.

params Object [] parameters