Tengo varios métodos, todos con la misma firma (parámetros y valores de retorno) pero diferentes nombres y aspectos internos de los métodos son diferentes. Quiero pasar el nombre del método a otro método que invoque el método pasado.
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 estoy tratando de hacer. Lo que no entiendo es cómo escribir el código RunTheMethod ya que necesito definir el parámetro.
Respuestas:
Puede usar el delegado Func en .net 3.5 como parámetro en su método RunTheMethod. El delegado de Func le permite especificar un método que toma una serie 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:
fuente
Action
lugar deFunc<string, int>
.Action<int,string>
corresponde a un método que toma 2 parámetros (int y string) y devuelve void.Func<double,string,int>
corresponde a un método que toma 2 parámetros (double
ystring
) y regresaint
. El último tipo especificado es el tipo de retorno. Puede usar este delegado para hasta 16 parámetros. Si de alguna manera necesita más, escriba su propio delegado comopublic delegate TResult Func<in T1, in T2, (as many arguments as you want), in Tn, out TResult>(T1 arg1, T2 arg2, ..., Tn argn);
. Por favor, corrígeme si no he entendido bien.Necesitas usar un delegado . En este caso, todos sus métodos toman un
string
parámetro y devuelven unint
- esto es simplemente representado por elFunc<string, int>
delegado 1 . Por lo tanto, su código puede ser correcto con un cambio tan simple como este:Los delegados tienen mucho más poder que esto, es cierto. Por ejemplo, con C # puede crear un delegado a partir de una expresión lambda , por lo que puede invocar su método de esta manera:
Eso creará una función anónima como esta:
y luego pasa ese delegado al
RunTheMethod
método.Puede usar delegados para suscripciones de eventos, ejecución asincrónica, devoluciones de llamada, todo tipo de cosas. Vale la pena leerlos, especialmente si desea usar LINQ. Tengo un artículo que trata principalmente sobre las diferencias entre delegados y eventos, pero de todos modos puede resultarle útil.
1 Esto se basa únicamente en el
Func<T, TResult>
tipo de delegado genérico en el marco; podrías declarar fácilmente el tuyo:y luego haga que el parámetro sea de tipo
MyDelegateType
.fuente
public **delegate** int MyDelegateType(string value)
?Del ejemplo de OP:
¡Puedes probar Action Delegate! Y luego llame a su método usando
O
Entonces simplemente llame al método
fuente
InvokeMethod
llamada lambda debería serRunTheMethod
en su lugarUso:
fuente
Para compartir una solución lo más completa posible, terminaré presentando tres formas diferentes de hacerlo, pero ahora voy a comenzar desde el principio más básico.
Una breve introduccion
Todos los lenguajes que se ejecutan sobre CLR ( Common Language Runtime ), como C #, F # y Visual Basic, funcionan en una VM, que ejecuta el código en un nivel superior a los lenguajes nativos como C y C ++ (que se compilan directamente en la máquina código). Se deduce que los métodos no son ningún tipo de bloque compilado, sino que son elementos estructurados que CLR reconoce. Por lo tanto, no puede pensar en pasar un método como parámetro, ¡porque los métodos no producen ningún valor por sí mismos, ya que no son expresiones! Más bien, son declaraciones, que se definen en el código CIL generado. Entonces, te enfrentarás al concepto de delegado.
¿Qué es un delegado?
Un delegado representa un puntero a un método. Como dije anteriormente, un método no es un valor, por lo tanto, hay una clase especial en lenguajes CLR
Delegate
, que envuelve cualquier método.Mira el siguiente ejemplo:
Tres formas diferentes, el mismo concepto detrás:
Forma 1
Use la
Delegate
clase especial directamente como el ejemplo anterior. El problema de esta solución es que su código estará desmarcado a medida que pase dinámicamente sus argumentos sin restringirlos a los tipos de aquellos en la definición del método.Modo 2
Además de la
Delegate
clase especial, el concepto de delegado se extiende a delegados personalizados, que son definiciones de métodos precedidos por ladelegate
palabra clave, y se comportan igual que los métodos normales. Por lo tanto, se verifican, por lo que obtendrá un código impecablemente seguro.Aquí hay un ejemplo:
Modo 3
Alternativamente, puede usar un delegado que ya ha sido definido dentro del estándar .NET:
Action
concluye unvoid
sin argumentos.Action<T1>
concluye unvoid
con un argumento.Action<T1, T2>
concluye avoid
con dos argumentos.Func<TR>
concluye una función conTR
tipo de retorno y sin argumentos.Func<T1, TR>
concluye una función con elTR
tipo de retorno y con un argumento.Func<T1, T2, TR>
concluye una función conTR
tipo de retorno y con dos argumentos.(La última solución es la que la mayoría de la gente publicó).
fuente
Func<T1,T2,TR>
Debe usar un
Func<string, int>
delegado, que representa una función que toma unstring
argumento y devuelve unint
:Entonces úsalo:
fuente
Test
método debería serreturn RunTheMethod(Method1);
Si desea cambiar el método que se llama en tiempo de ejecución, le recomendaría usar un delegado: http://www.codeproject.com/KB/cs/delegates_step1.aspx
Le permitirá crear un objeto para almacenar el método para llamar y puede pasarlo a sus otros métodos cuando sea necesario.
fuente
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 basado en complementos, 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
Menu
objeto real porque el marco puede implementarse en otras plataformas que no tienenMenu
interfaz de usuario objetos. Agregar información general sobre el menú es bastante fácil, pero permitir que el desarrollador del complemento tenga la libertad suficiente para crear la devolución de llamada para cuando se hace clic en el menú resultó ser una molestia. ¡Hasta que caí en la cuenta de que estaba tratando de reinventar la rueda y los menús normales llaman y activan la devolución de llamada 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.
fuente
Aquí hay un ejemplo que puede ayudarlo a comprender mejor cómo pasar una función como parámetro.
Suponga que tiene Padres página y desea abrir una ventana emergente niño. En la página principal hay un cuadro de texto que debe rellenarse basándose en el cuadro de texto emergente secundario.
Aquí necesitas crear un delegado.
Parent.cs // declaración de delegados public delegate void FillName (String FirstName);
Ahora cree una función que llene su cuadro de texto y la función debería asignar delegados
Ahora, al hacer clic en el botón, debe abrir una ventana emergente secundaria.
En el constructor ChildPopUp, debe crear el parámetro de 'tipo de delegado' de la página principal //
ChildPopUp.cs
fuente
Si desea pasar Método como parámetro, use:
fuente
Aquí hay un ejemplo sin parámetro: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
con parámetros: http://www.daniweb.com/forums/thread98148.html#
básicamente pasa una matriz de objetos junto con el nombre del método. luego usa ambos con el método Invoke.
parámetros de Object [] params
fuente
La segunda clase es Client, que utilizará la clase de almacenamiento. Tiene un método Main que crea una instancia de PersonDB, y llama al método Process de ese objeto con un método que se define en la clase Client.
fuente