Co to jest Func, jak i kiedy jest stosowany
Co to jest Func<>
i w jakim celu się go stosuje?
6 answers
Func<T>
jest predefiniowanym typem delegata dla metody, która zwraca jakąś wartość typu T
.
Innymi słowy, możesz użyć tego typu, aby odwołać się do metody, która zwraca pewną wartość T
. Np.
public static string GetMessage() { return "Hello world"; }
Może być odwołany w ten sposób
Func<string> f = GetMessage;
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-09-02 07:58:19
Pomyśl o tym jak o zastępstwie. Może to być bardzo przydatne, gdy masz kod, który podąża za określonym wzorcem, ale nie musi być powiązany z żadną konkretną funkcjonalnością.
Na przykład rozważ metodę rozszerzenia Enumerable.Select
.
- wzór jest następujący: dla każdego elementu w sekwencji wybierz jakąś wartość z tego elementu (np. właściwość) i utwórz nową sekwencję składającą się z tych wartości.
- the placeholder is: some selector function that actually gets wartości dla sekwencji opisanej powyżej.
Ta metoda przyjmuje Func<T, TResult>
zamiast jakiejkolwiek konkretnej funkcji. Pozwala to na użycie go w dowolnym kontekście , w którym powyższy wzór ma zastosowanie.
Więc na przykład, powiedzmy, że mam {[5] } i chcę tylko nazwisko każdej osoby na liście. Mogę to zrobić:
var names = people.Select(p => p.Name);
Lub powiedzmy, że chcę wiek każdej osoby:
var ages = people.Select(p => p.Age);
Od razu widać, jak udało mi się wykorzystać ten sam kod reprezentując wzór (z Select
) z dwoma różnymi funkcjami (p => p.Name
i p => p.Age
).
Alternatywą byłoby napisanie innej wersji Select
za każdym razem, gdy chcesz zeskanować sekwencję w poszukiwaniu innego rodzaju wartości. Aby więc osiągnąć taki sam efekt jak powyżej, potrzebowałbym:
// Presumably, the code inside these two methods would look almost identical;
// the only difference would be the part that actually selects a value
// based on a Person.
var names = GetPersonNames(people);
var ages = GetPersonAges(people);
Z delegatem działającym jako zastępczy, uwalniam się od konieczności wypisywania tego samego wzoru w kółko w takich przypadkach.
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-09-02 08:00:07
Func<T1, T2, ..., Tn, Tr>
reprezentuje funkcję, która przyjmuje (T1, T2, ..., Tn) argumenty i zwraca Tr.
Na przykład, jeśli masz funkcję:
double sqr(double x) { return x * x; }
Możesz zapisać ją jako jakąś zmienną funkcji:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
A następnie użyj dokładnie tak, jak używasz sqr:
f1(2);
Console.WriteLine(f2(f1(4)));
Itd.
Pamiętaj jednak, że jest to delegat, aby uzyskać bardziej zaawansowane informacje, zapoznaj się z dokumentacją.
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-09-02 07:54:44
Func<T1,R>
i inne predefiniowane generyczne Func
(Func<T1,T2,R>
, Func<T1,T2,T3,R>
i inne) są delegatami generycznymi, które zwracają Typ ostatniego parametru generycznego.
Jeśli masz funkcję, która musi zwracać różne typy, w zależności od parametrów, możesz użyć delegata Func
, określającego Typ zwracania.
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-09-02 07:57:45
Jest to tylko predefiniowany ogólny delegat. Używając go nie musisz deklarować każdego delegata. Istnieje inny predefiniowany delegat Action<T, T2...>
, który jest taki sam, ale zwraca void.
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-09-02 08:02:47
Uważam, że Func<T>
jest bardzo przydatny, gdy tworzę komponent, który musi być spersonalizowany "w locie".
Weźmy ten bardzo prosty przykład: składnik PrintListToConsole<T>
.
Bardzo prosty obiekt, który wyświetla tę listę obiektów w konsoli. Chcesz, aby programista, który go używa, spersonalizował wynik.
Na przykład, chcesz pozwolić mu zdefiniować konkretny typ formatu liczb i tak dalej.
Bez Func
Najpierw musisz stworzyć interfejs dla klasy, która pobiera dane wejściowe i tworzy ciąg znaków do wydrukowania na konsoli.
interface PrintListConsoleRender<T> {
String Render(T input);
}
Następnie musisz utworzyć klasę PrintListToConsole<T>
, która pobiera wcześniej utworzony interfejs i używa go nad każdym elementem listy.
class PrintListToConsole<T> {
private PrintListConsoleRender<T> _renderer;
public void SetRenderer(PrintListConsoleRender<T> r) {
// this is the point where I can personalize the render mechanism
_renderer = r;
}
public void PrintToConsole(List<T> list) {
foreach (var item in list) {
Console.Write(_renderer.Render(item));
}
}
}
Programista, który musi użyć Twojego komponentu musi:
-
Implementacja interfejsu
-
Przekazać prawdziwą klasę
PrintListToConsole
class MyRenderer : PrintListConsoleRender<int> { public String Render(int input) { return "Number: " + input; } } class Program { static void Main(string[] args) { var list = new List<int> { 1, 2, 3 }; var printer = new PrintListToConsole<int>(); printer.SetRenderer(new MyRenderer()); printer.PrintToConsole(list); string result = Console.ReadLine(); } }
Korzystanie z Func to dużo prostsze
Wewnątrz komponentu definiujesz parametr typu Func<T,String>
, który reprezentuje interfejs funkcji , która pobiera parametr wejściowy typu T i zwraca łańcuch (wyjście dla konsoli)
class PrintListToConsole<T> {
private Func<T, String> _renderFunc;
public void SetRenderFunc(Func<T, String> r) {
// this is the point where I can set the render mechanism
_renderFunc = r;
}
public void Print(List<T> list) {
foreach (var item in list) {
Console.Write(_renderFunc(item));
}
}
}
Kiedy programista używa Twojego komponentu, po prostu przekazuje do niego implementację typu Func<T, String>
, czyli funkcję, która tworzy wyjście dla konsoli.
class Program {
static void Main(string[] args) {
var list = new Array[1, 2, 3];
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
printer.Print();
string result = Console.ReadLine();
}
}
Func<T>
pozwala zdefiniować ogólny interfejs metody w locie.
Definiujesz, jakiego typu jest wejście i jaki jest typ wyjścia.
Proste i zwięzłe.
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-06-25 09:49:37