Metoda Pass jako parametr za pomocą C#

Mam kilka metod, wszystkie z tym samym podpisem (parametry i wartości zwrotne), ale różne nazwy i wewnętrzne metody są różne. Chcę przekazać nazwę metody do uruchomienia do innej metody, która wywoła metodę passed in.

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

Ten kod nie działa, ale to właśnie próbuję zrobić. Nie rozumiem, jak napisać kod RunTheMethod, ponieważ muszę zdefiniować parametr.

Author: carefulnow1, 2010-01-18

10 answers

Możesz użyć delegata Func w. Net 3.5 jako parametru w metodzie RunTheMethod. Delegat Func pozwala określić metodę, która pobiera szereg parametrów określonego typu i Zwraca pojedynczy argument określonego typu. Oto przykład, który powinien zadziałać:

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
Author: Egil Hansen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-17 21:08:10

Musisz użyć delegata. W tym przypadku wszystkie metody pobierają parametr string i zwracają int - jest to najprościej reprezentowane przez delegata Func<string, int> 1. Tak więc Twój kod może stać się poprawny z tak prostą zmianą jak ta:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}
Delegaci mają o wiele większą władzę. Na przykład w C# możesz utworzyć delegata z wyrażenia lambda , więc możesz wywołać swoją metodę w ten sposób:
RunTheMethod(x => x.Length);

To stworzy funkcja anonimowa jak ta:

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

, a następnie przekazać ten delegat do metody RunTheMethod.

Możesz używać delegatów do subskrypcji zdarzeń, asynchronicznej realizacji, wywołań zwrotnych-wszelkiego rodzaju rzeczy. Warto o nich poczytać, szczególnie jeśli chcemy korzystać z LINQ. Mam Artykuł, który jest głównie o różnicach między delegatami i wydarzeniami, ale i tak może się okazać przydatny.


1 jest to po prostu oparte na generic Func<T, TResult> typ delegata w frameworku; możesz łatwo zadeklarować swój własny:

public delegate int MyDelegateType(string value)

A następnie niech parametr będzie Typu MyDelegateType.

 311
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-26 05:31:29

Możesz również spróbować 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;
 }

A następnie wywołaj swoją metodę używając

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

Lub

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

Następnie po prostu wywołaj metodę

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

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
 87
Author: Humble Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-17 15:29:44
public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Użycie:

var ReturnValue = Runner(() => GetUser(99));
 25
Author: kravits88,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-14 02:50:18

Powinieneś użyć delegata Func<string, int>, który reprezentuje funkcję przyjmującą string jako argument i zwracającą int:

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

Następnie użyj go:

public bool Test() {
    return RunTheMethod(Method1);
}
 10
Author: Bruno Reis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-23 21:37:09

Jeśli chcesz mieć możliwość zmiany, która metoda jest wywoływana w czasie wykonywania, polecam użycie delegata: http://www.codeproject.com/KB/cs/delegates_step1.aspx

Pozwoli Ci utworzyć obiekt do przechowywania metody do wywołania i możesz przekazać ją innym metodom, gdy jest to potrzebne.

 6
Author: MadcapLaugher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-17 21:05:52

Chociaż przyjęta odpowiedź jest absolutnie poprawna, chciałbym podać dodatkową metodę.

Wylądowałem tutaj po tym, jak sam szukałem rozwiązania podobnego pytania. Buduję framework oparty na wtyczkach, a w jego ramach chciałem, aby ludzie mogli dodawać elementy menu do menu aplikacji do ogólnej listy bez wystawiania rzeczywistego obiektu Menu, ponieważ framework może zostać wdrożony na innych platformach, które nie mają Menu obiektów UI. Dodawanie ogólnych informacji o menu jest wystarczająco łatwe, ale pozwalając twórcy plugin wystarczająco dużo swobody, aby utworzyć callback po kliknięciu menu okazało się być bólem. Dopóki nie dotarło do mnie, że próbowałem ponownie wynaleźć koło i normalne połączenia menu i wywołać oddzwanianie od zdarzeń!

Więc rozwiązanie, tak proste, jak się wydaje, gdy się je uświadomi, umknęło mi aż do teraz.

Po prostu utwórz osobne klasy dla każdej z twoich obecnych metod, odziedziczonych po bazie, jeśli musisz, i po prostu dodaj Zdarzenie opiekun dla każdego.

 2
Author: Wobbles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-29 13:48:34

Aby podzielić się jak najbardziej kompletnym rozwiązaniem, skończę z przedstawieniem trzech różnych sposobów działania, ale teraz zacznę od najbardziej podstawowej zasady.


Krótkie wprowadzenie

Wszystkie języki CLR (Common Language Runtime) (takie jak C# i Visual Basic) pracują pod maszyną wirtualną o nazwie CLI (common Language Interpreter), która uruchamia kod na wyższym poziomie niż języki natywne, takie jak C i C++ (które bezpośrednio kompilują się na maszynie kod). Wynika z tego, że metody nie są żadnym rodzajem skompilowanego bloku, ale są po prostu strukturyzowanymi elementami, które CLR rozpoznaje i używa do wyciągania swojego ciała i przerabiania go do wbudowanych instrukcji kodu maszynowego. Nie możesz więc myśleć o przekazaniu metody jako parametru, ponieważ metoda sama w sobie nie generuje żadnej wartości: nie jest poprawnym wyrażeniem! Więc potkniesz się o koncepcję delegata.
Co to jest delegat?

Delegat reprezentuje wskaźnik za metodę. Ponieważ (jak powiedziałem powyżej) metoda nie jest wartością, istnieje specjalna klasa w językach CLR: Delegate. Ta klasa otacza dowolną metodę i można ją w sposób niejawny przypisać dowolnej metodzie.

Spójrz na następujący przykład użycia:

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

Trzy sposoby:

  • Sposób 1
    Użyj klasy specjalnej Delegate bezpośrednio jako przykład powyżej. Problem tego rozwiązania polega na tym, że Twój kod będzie odznaczony, gdy przekazujesz dynamicznie swój argumenty bez ograniczania ich do typów zawartych w deklaracji metody.

  • Sposób 2/3 Oprócz specjalnej klasy Delegate, koncepcja delegatów rozprzestrzenia się na niestandardowe delegaty, które są deklaracjami metod poprzedzonych słowem kluczowym delegate i zachowują się jak normalna metoda. Są tak sprawdzone, a Ty znajdziesz kod" perfect ".

Spójrz na następujący przykład:

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

Druga opcja w ten sposób aby nie pisać własnego delegata niestandardowego, należy użyć jednego z nich zadeklarowanego w bibliotekach systemowych:

  • Action owija void bez argumentów.
  • Action<T1> owija void jednym argumentem.
  • Action<T1, T2> owija void dwoma argumentami.
  • i tak dalej...
  • Func<TR> zawija funkcję z typem zwracanym TR bez argumentów.
  • Func<TR, T1> zawija funkcję z typem zwracanym TR i z jednym argumentem.
  • Func<TR, T1, T2> otacza funkcję z TR return type i z dwoma argumentami.
  • i tak dalej...

(to ostatnie rozwiązanie polega na tym, że wiele osób opublikowało.)

 2
Author: Davide Cannizzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 14:35:52

Oto przykład, który pomoże Ci lepiej zrozumieć, jak przekazać funkcję jako parametr.

Załóżmy, że masz stronę rodzica i chcesz otworzyć wyskakujące okno dziecka. Na stronie nadrzędnej znajduje się pole tekstowe, które należy wypełnić w oparciu o pole tekstowe Popup potomne.

Tutaj musisz utworzyć delegata.

Rodzic.cs // deklaracja delegatów delegat publiczny void FillName (String FirstName);

Teraz Utwórz funkcję, która wypełni twoje pole tekstowe i funkcja powinny mapować delegatów

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

Teraz po kliknięciu przycisku musisz otworzyć wyskakujące okno dziecka.

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

         p.Show();

    }

W Konstruktorze ChildPopUp musisz utworzyć parametr 'typ delegata' strony nadrzędnej //

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
Author: Shrikant-Divyanet Solution,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 09:58:29

Oto przykład bez parametru: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

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

W zasadzie przekazujesz tablicę obiektów wraz z nazwą metody. następnie używasz obu z metodą Invoke.

Params obiekt [] parametry

 0
Author: Jeremy Samuel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-17 21:04:36