Mam kilka metod o tej samej sygnaturze (parametry i zwracane wartości), ale różne nazwy i elementy wewnętrzne metod są różne. Chcę przekazać nazwę metody do uruchomienia do innej metody, która wywoła przekazaną metodę.
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 staram się to zrobić. Nie rozumiem, jak napisać kod RunTheMethod, ponieważ muszę zdefiniować parametr.
Odpowiedzi:
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 działać:
źródło
Action
zamiastFunc<string, int>
.Action<int,string>
odpowiada metodzie, która przyjmuje 2 parametry (int i ciąg) i zwraca wartość void.Func<double,string,int>
odpowiada metodzie, która przyjmuje 2 parametry (double
istring
) i zwracaint
. Ostatni określony typ to typ zwracany. Możesz użyć tego delegata dla maksymalnie 16 parametrów. Jeśli potrzebujesz czegoś więcej, napisz swojego delegata jakopublic delegate TResult Func<in T1, in T2, (as many arguments as you want), in Tn, out TResult>(T1 arg1, T2 arg2, ..., Tn argn);
. Proszę mnie poprawić, jeśli źle zrozumiałem.Musisz użyć delegata . W takim przypadku wszystkie metody pobierają
string
parametr i zwracają anint
- jest to najprościej reprezentowane przezFunc<string, int>
delegata 1 . Aby Twój kod mógł być poprawny, wystarczy tak prosta zmiana:Trzeba przyznać, że delegaci mają o wiele więcej władzy. Na przykład za pomocą C # możesz utworzyć delegata z wyrażenia lambda , abyś mógł wywołać swoją metodę w ten sposób:
Spowoduje to utworzenie anonimowej funkcji:
a następnie przekaż tego delegata do
RunTheMethod
metody.Możesz używać delegatów do subskrypcji zdarzeń, wykonywania asynchronicznego, wywołań zwrotnych - wszelkiego rodzaju rzeczy. Warto o nich poczytać, szczególnie jeśli chcesz korzystać z LINQ. Mam artykuł, który dotyczy głównie różnic między delegatami i wydarzeniami, ale i tak może ci się przydać.
1 Jest to oparte na ogólnym
Func<T, TResult>
typie delegata w ramach; możesz łatwo zadeklarować własne:a następnie ustaw
MyDelegateType
zamiast tego parametr type .źródło
public **delegate** int MyDelegateType(string value)
?Z przykładu OP:
Możesz spróbować Action Delegate! A następnie wywołaj metodę za pomocą
Lub
Następnie po prostu wywołaj metodę
źródło
InvokeMethod
rozmowa lambda powinna byćRunTheMethod
zamiastStosowanie:
źródło
Aby podzielić się możliwie jak najbardziej kompletnym rozwiązaniem, przedstawię trzy różne sposoby działania, ale teraz zacznę od najbardziej podstawowej zasady.
Krótkie wprowadzenie
Wszystkie języki działające na CLR ( Common Language Runtime ), takie jak C #, F # i Visual Basic, działają pod maszyną wirtualną, która uruchamia kod na wyższym poziomie niż języki rodzime, takie jak C i C ++ (które kompilują się bezpośrednio na maszynie kod). Wynika z tego, że metody nie są żadnym skompilowanym blokiem, ale są tylko elementami strukturalnymi, które rozpoznaje CLR. Dlatego nie możesz pomyśleć o przekazaniu metody jako parametru, ponieważ metody same nie generują żadnych wartości, ponieważ nie są wyrażeniami! Są to raczej instrukcje zdefiniowane w wygenerowanym kodzie CIL. Więc napotkasz koncepcję delegata.
Kim jest delegat?
Delegat reprezentuje wskaźnik do metody. Jak powiedziałem powyżej, metoda nie jest wartością, dlatego istnieje specjalna klasa w językach CLR
Delegate
, która zawiera dowolną metodę.Spójrz na następujący przykład:
Trzy różne sposoby, ta sama koncepcja:
Sposób 1
Użyj
Delegate
specjalnej klasy bezpośrednio jak w powyższym przykładzie. Problemem tego rozwiązania jest to, że Twój kod nie będzie zaznaczony podczas dynamicznego przekazywania argumentów bez ograniczania ich do typów z definicji metody.Sposób 2
Oprócz
Delegate
klasy specjalnej, koncepcja delegata rozprzestrzenia się na niestandardowych delegatów, które są definicjami metod poprzedzonych przezdelegate
słowem kluczowym i zachowują się tak samo jak normalne metody. Są one w ten sposób sprawdzane, więc opracujesz bezbłędnie bezpieczny kod.Oto przykład:
Sposób 3
Alternatywnie możesz użyć delegata, który został już zdefiniowany w .NET Standard:
Action
podsumowujevoid
bez argumentów.Action<T1>
podsumowujevoid
jednym argumentem.Action<T1, T2>
podsumowujevoid
z dwoma argumentami.Func<TR>
podsumowuje funkcjęTR
typu zwracanego i bez argumentów.Func<T1, TR>
podsumowuje funkcję zTR
typem zwracanym i jednym argumentem.Func<T1, T2, TR>
kończy funkcję za pomocąTR
typem zwracanym i dwoma argumentami.(To drugie rozwiązanie jest tym, które opublikowało najwięcej osób).
źródło
Func<T1,T2,TR>
Należy użyć
Func<string, int>
delegata, który reprezentuje funkcję przyjmującąstring
jako argument i zwracającąint
:Następnie użyj go:
źródło
Test
Metoda powinna byćreturn RunTheMethod(Method1);
Jeśli chcesz zmienić metodę, która jest wywoływana w czasie wykonywania, polecam użycie delegata: http://www.codeproject.com/KB/cs/delegates_step1.aspx
Pozwoli ci to stworzyć obiekt do przechowywania metody do wywołania i możesz przekazać ją innym metodom, gdy będzie to potrzebne.
źródło
Chociaż zaakceptowana odpowiedź jest absolutnie poprawna, chciałbym podać dodatkową metodę.
Skończyło się na tym, że szukałem rozwiązania podobnego pytania. Buduję strukturę opartą na wtyczkach i jako część tego chciałem, aby ludzie mogli dodawać elementy menu do menu aplikacji do ogólnej listy bez ujawniania rzeczywistego
Menu
obiektu, ponieważ struktura może być wdrażana na innych platformach, które nie mająMenu
interfejsu użytkownika przedmioty Dodawanie ogólnych informacji o menu jest dość łatwe, ale pozwolenie twórcy wtyczki na swobodę tworzenia oddzwaniania, gdy kliknięcie menu okazało się być uciążliwe. Dopóki nie przyszło mi do głowy, że próbuję na nowo wynaleźć koło i normalne wywołanie menu i wywołać oddzwanianie od zdarzeń!Tak więc rozwiązanie, tak proste, jak się wydaje, kiedy się zorientujesz, umykało mi do tej pory.
Po prostu utwórz oddzielne klasy dla każdej z twoich obecnych metod, w razie potrzeby odziedziczone z bazy, i po prostu dodaj do każdej z nich procedurę obsługi zdarzeń.
źródło
Oto przykład, który pomoże ci lepiej zrozumieć, jak przekazać funkcję jako parametr.
Załóżmy, że masz stronę nadrzędną i chcesz otworzyć podrzędne okno podręczne. Na stronie nadrzędnej znajduje się pole tekstowe, które powinno zostać wypełnione na podstawie podrzędnego pola tekstowego wyskakującego.
Tutaj musisz utworzyć delegata.
Parent.cs // deklaracja delegatów public delegate void FillName (String FirstName);
Teraz utwórz funkcję, która wypełni pole tekstowe, a funkcja powinna mapować delegatów
Teraz po kliknięciu przycisku musisz otworzyć okno podręczne Dziecko.
W konstruktorze ChildPopUp musisz utworzyć parametr „typu delegata” nadrzędnej // strony
ChildPopUp.cs
źródło
Jeśli chcesz przekazać metodę jako parametr, użyj:
źródło
Oto przykład bez parametru: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
z parametrami: http://www.daniweb.com/forums/thread98148.html#
w zasadzie przekazujesz tablicę obiektów wraz z nazwą metody. następnie używasz obu metod Invoke.
params Parametry Object []
źródło
Druga klasa to Klient, który będzie korzystał z klasy pamięci. Ma metodę Main, która tworzy instancję PersonDB i wywołuje metodę Process tego obiektu za pomocą metody zdefiniowanej w klasie Client.
źródło