Passer la méthode comme paramètre en utilisant C#

j'ai plusieurs méthodes toutes avec la même signature (paramètres et valeurs de retour) mais les noms différents et les internes des méthodes sont différents. Je veux passer le nom de la méthode à exécuter à une autre méthode qui va invoquer la méthode passée.

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

ce code ne fonctionne pas mais c'est ce que j'essaie de faire. Ce que je ne comprends pas c'est comment écrire le code RunTheMethod puisque j'ai besoin de définir le paramètre.

533
demandé sur carefulnow1 2010-01-18 00:01:01

10 réponses

vous pouvez utiliser le delegate Func dans .net 3.5 comme paramètre dans votre méthode RunTheMethod. Le délégué Func permet de spécifier une méthode qui prend un certain nombre de paramètres d'un type spécifique et renvoie un seul argument d'un type spécifique. Voici un exemple qui devrait fonctionner:

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);
    }
}
666
répondu Egil Hansen 2010-01-17 21:08:10

Vous devez utiliser un délégué . Dans ce cas, toutes vos méthodes prennent un paramètre string et renvoient un paramètre int - ceci est très simplement représenté par le Func<string, int> délégué 1 . Ainsi votre code peut devenir correct avec un changement aussi simple que ceci:

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

les Délégués ont beaucoup plus de pouvoir que cela, certes. Par exemple, avec C# vous pouvez créer un délégué à partir d'un lambda expression , pour que vous puissiez invoquer votre méthode de cette façon:

RunTheMethod(x => x.Length);

qui va créer une fonction anonyme comme celle-ci:

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

et ensuite passer ce délégué à la méthode RunTheMethod .

vous pouvez utiliser les délégués pour les abonnements à des événements, l'exécution asynchrone, les callbacks - toutes sortes de choses. Cela vaut la peine de les lire, surtout si vous voulez utiliser LINQ. J'ai un article qui est principalement sur les différences entre les délégués et les événements, mais vous pouvez trouver utile de toute façon.


1 c'est juste basé sur le type de délégué générique Func<T, TResult> dans le framework; vous pouvez facilement déclarer votre propre:

public delegate int MyDelegateType(string value)

et ensuite faire le paramètre être de type MyDelegateType à la place.

311
répondu Jon Skeet 2016-09-26 05:31:29

vous pouvez aussi essayer action Delegate!

 public static int Method1(string mystring)
 {
      return 1;
 }

 public static int Method2(string mystring)
 {
     return 2;
 }

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();
      return true;
 }

et ensuite appelez votre méthode en utilisant

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

ou

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

alors simplement appeler la méthode

Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
87
répondu Humble Coder 2015-07-17 15:29:44
public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Utilisation:

var ReturnValue = Runner(() => GetUser(99));
25
répondu kravits88 2014-08-14 02:50:18

vous devez utiliser un Func<string, int> délégué, qui représente une fonction prenant un string comme argument et retournant un int :

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

puis l'utiliser:

public bool Test() {
    return RunTheMethod(Method1);
}
10
répondu Bruno Reis 2013-08-23 21:37:09

si vous voulez la possibilité de changer quelle méthode est appelée à l'exécution, je recommande l'utilisation d'un délégué: http://www.codeproject.com/KB/cs/delegates_step1.aspx

il vous permettra de créer un objet pour stocker la méthode à appeler et vous pouvez passer cela à vos autres méthodes quand il est nécessaire.

6
répondu MadcapLaugher 2010-01-17 21:05:52

bien que la réponse acceptée soit absolument correcte, j'aimerais fournir une méthode supplémentaire.

j'ai atterri ici après avoir fait ma propre recherche d'une solution à une question similaire. Je suis en train de construire un framework piloté par plugin, et dans le cadre de cela je voulais que les gens puissent ajouter des éléments de menu au menu applications à une liste générique sans exposer un objet Menu réel parce que le framework peut se déployer sur d'autres plateformes qui n'ont pas Menu UI objet. Ajouter des informations générales sur le menu est assez facile, mais permettre au développeur de plugin assez de liberté pour créer le callback pour quand le menu est cliqué s'est avéré être une douleur. Jusqu'à ce que je me rende compte que j'essayais de réinventer la roue et l'appel normal des menus et de déclencher le rappel des événements!

donc la solution, aussi simple que cela paraisse une fois que vous vous en rendez compte, m'a échappé jusqu'à maintenant.

il suffit de créer des classes séparées pour chacun de vos méthodes courantes, héritées d'une base si vous le DEVEZ, et ajoutez simplement un gestionnaire d'événements à chacune.

2
répondu Wobbles 2015-03-29 13:48:34

pour partager une solution aussi complète que possible, je vais finir par présenter trois façons différentes de faire, mais maintenant je vais commencer par le principe le plus fondamental.


Brève introduction

All CLR ( Common Language Runtime ) langages (comme C# et Visual Basic) travaillent sous une machine virtuelle appelée CLI ( Langage Commun Interprète ) qui se déroule à l' code à un niveau plus élevé que les langues natives comme C et C++ (qui compilent directement le code machine). Il s'ensuit que les méthodes ne sont pas n'importe quel type de bloc compilé, mais ils sont juste des éléments structurés qui CLR reconnaissent et utilisent pour tirer leur corps et le réajuster aux instructions en ligne du code de la machine. Ainsi, vous ne pouvez pas penser à passer une méthode comme paramètre, parce qu'une méthode ne produit pas de valeur par elle-même: ce n'est pas une expression valide! Donc, vous allez tomber sur le délégué concept.


Qu'est-ce qu'un délégué?

Un délégué représente un pointeur sur une méthode. En raison de (comme je l'ai dit plus haut) une méthode n'est pas une valeur, il y a une classe spéciale dans les langues CLR: Delegate . Cette classe encapsule la méthode, et vous pouvez implicitement convertie en une méthode pour cela.

regardez l'exemple d'utilisation suivant:

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

les trois façons:

  • Voie 1

    Utilisez la classe spéciale Delegate directement comme exemple ci-dessus. Le problème de cette solution est que votre code ne sera pas vérifié que vous passez dynamiquement vos arguments sans les restreindre aux types de ceux dans la déclaration de méthode.

  • Façon 2/3 Outre le Delegate spécial classe, le concept de délégué se propage aux délégués de coutume, qui sont des déclarations de méthodes précédées par le mot-clé delegate et ils se comportent comme une méthode normale. Ils sont ainsi vérifiés, et vous viendrez à un " parfait code.

Regardez l'exemple suivant:

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");
}

une deuxième option par cette façon de ne pas écrire votre propre délégué personnalisé est d'utiliser l'un d'eux déclaré dans bibliothèques système:

  • Action enveloppe void sans arguments.
  • Action<T1> enveloppe void avec un argument.
  • Action<T1, T2> enveloppe void avec deux arguments.
  • et ainsi de suite...
  • Func<TR> enveloppe une fonction avec TR type de retour et sans arguments.
  • Func<TR, T1> encapsule un fonction avec le type de retour TR et avec un argument.
  • Func<TR, T1, T2> enveloppe une fonction avec TR type de retour et avec deux arguments.
  • et ainsi de suite...

(cette dernière solution est que beaucoup de gens postés.)

2
répondu Davide Cannizzo 2018-05-15 14:35:52

Voici un exemple Qui peut vous aider à mieux comprendre comment passer une fonction en paramètre.

supposez que vous avez Parent page et vous voulez ouvrir une fenêtre popup enfant. Dans la page parent il y a une boîte de texte qui doit être remplie en se basant sur la boîte de texte popup enfant.

Ici, vous devez créer un délégué.

Parent.cs // déclaration des délégués représentant public nul FillName (String FirstName);

maintenant créer une fonction qui remplira votre boîte de texte et la fonction devrait cartographier les délégués

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

maintenant sur le bouton cliquez sur vous devez ouvrir une fenêtre popup enfant.

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

         p.Show();

    }

dans le constructeur ChildPopUp vous devez créer le paramètre 'Type de délégué' de parent / / page

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
répondu Shrikant-Divyanet Solution 2016-05-25 09:58:29

voici un exemple sans paramètre: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

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

vous passez essentiellement dans un tableau d'objets avec le nom de la méthode. vous utilisez alors les deux avec la méthode Invoke.

params objet[] params

0
répondu Jeremy Samuel 2010-01-17 21:04:36