Pregunta 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 intento hacer. Lo que no entiendo es cómo escribir el código RunTheMethod ya que necesito definir el parámetro.


521
2018-01-17 21:01


origen


Respuestas:


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<string, int> myMethodName)
    {
        //... do stuff
        int i = myMethodName("My String");
        //... do more stuff
        return true;
    }

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

653
2018-01-17 21:08



Necesitas usar un delegar. En este caso, todos sus métodos toman una string parámetro y devolver un int - esto es simplemente representado por el Func<string, int> delegar1. Entonces su código puede volverse correcto con un cambio tan simple como este:

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

Los delegados tienen mucho más poder que esto, en verdad. Por ejemplo, con C # puede crear un delegado de un expresión lambda, por lo que podría invocar su 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 a la RunTheMethod método.

Puede usar delegados para suscripciones de eventos, ejecución asincrónica, devoluciones de llamadas, todo tipo de cosas. Vale la pena leerlos, especialmente si quieres usar LINQ. Yo tengo un artículo cual es principalmente acerca de las diferencias entre los delegados y los eventos, pero puede ser útil de todos modos.


1 Esto solo se basa en el genérico Func<T, TResult> delegar tipo en el marco; usted podría declarar fácilmente el suyo:

public delegate int MyDelegateType(string value)

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


305
2018-01-17 21:02



¡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<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));

85
2017-10-14 10:40



public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Uso:

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

23
2017-08-14 02:50



Deberías usar un Func<string, int> delegado, que representa una función tomando una string como argumento y devolver un int:

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

Entonces úsalo:

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

10
2018-01-17 21:03



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.


6
2018-01-17 21:05



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 plugin, 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 real Menu objeto porque el marco puede implementar en otras plataformas que no tienen Menu Objetos de UI. Agregar información general sobre el menú es bastante fácil, pero permitir que el desarrollador del complemento tenga suficiente libertad para crear la devolución de llamada 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 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.


1
2018-03-29 13:48



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

Supongamos que tiene Padre página 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        // declaración de delegados        delegado público void FillName (String FirstName);

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

//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;
    }

1
2017-09-24 11:50