To tylko skrót dla delegatów z określonym podpisem. Aby w pełni zrozumieć poniższe odpowiedzi, musisz zrozumieć delegatów ;-)
Theo Lenndorff
2
W odpowiedzi @Oded jest napisaneIf you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
LCJ
Odpowiedzi:
76
Func<T> jest predefiniowanym typem delegata dla metody, która zwraca pewną wartość typu T .
Innymi słowy, możesz użyć tego typu, aby odwołać się do metody, która zwraca pewną wartość T. Na przykład
Ale może również reprezentować statyczną jednoargumentową funkcję =)
Ark-kun
2
@ Ark-kun nie, to nie jest poprawne. Definicja Func<T>jest delegate TResult Func<out TResult>(). Żadnych argumentów.Func<T1, T2>byłaby funkcją, która przyjmuje jeden argument.
Brian Rasmussen
4
Nie, mam rację. static int OneArgFunc(this string i) { return 42; }Func<int> f = "foo".OneArgFunc;. =)
Ark-kun
1
To wyjątkowa metoda rozszerzania.
Brian Rasmussen
Jedyną specjalną rzeczą jest Extensionatrybut, który jest odczytywany tylko przez kompilatory C # / VB.Net, a nie CLR. Zasadniczo metody instancji (w przeciwieństwie do funkcji statycznych) mają ukryty zerowy parametr „ten”. Zatem metoda instancji z 1 argumentem jest bardzo podobna do funkcji statycznej z 2 argumentami. Następnie mamy delegatów, którzy przechowują obiekt docelowy i wskaźnik funkcji . Delegaci mogą przechowywać pierwszy argument w miejscu docelowym lub tego nie robić.
Ark-kun,
87
Potraktuj to jako symbol zastępczy. Może to być całkiem przydatne, gdy masz kod, który jest zgodny z określonym wzorcem, ale nie musi być powiązany z żadną konkretną funkcjonalnością.
Weźmy na przykład pod uwagę Enumerable.Selectmetodę rozszerzenia.
wzór jest: za każdy element w sekwencji, wybierz jakąś wartość z tej pozycji (na przykład nieruchomości) i utworzyć nową sekwencję składającą się z tymi wartościami.
Symbol zastępczy to: jakaś funkcja selektora, która w rzeczywistości pobiera wartości dla sekwencji opisanej powyżej.
Ta metoda przyjmuje Func<T, TResult>zamiast dowolnej konkretnej funkcji. Pozwala to na użycie go w dowolnym kontekście, w którym ma zastosowanie powyższy wzorzec.
Na przykład, powiedzmy, że mam plik List<Person> i chcę tylko nazwiska każdej osoby na liście. Mogę to zrobić:
var names = people.Select(p => p.Name);
Albo powiedz, ż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ący wzorzec (z Select) z dwiema różnymi funkcjami ( p => p.Nameip => p.Age ).
Alternatywą byłoby zapisanie innej wersji za Selectkażdym razem, gdy chciałbyś przeskanować sekwencję pod kątem innego rodzaju wartości. Aby 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);
Dzięki delegatowi pełniącemu rolę elementu zastępczego, uwalniam się od konieczności ciągłego pisania tego samego wzoru w takich przypadkach.
Następnie musisz utworzyć klasę, PrintListToConsole<T>która przejmuje poprzednio utworzony interfejs i używa go do każdego elementu listy.
classPrintListToConsole<T>{privatePrintListConsoleRender<T> _renderer;publicvoidSetRenderer(PrintListConsoleRender<T> r){// this is the point where I can personalize the render mechanism
_renderer = r;}publicvoidPrintToConsole(List<T>list){foreach(var item inlist){Console.Write(_renderer.Render(item));}}}
Deweloper, który musi użyć Twojego komponentu, musi:
Wewnątrz komponentu definiujesz parametr typu, Func<T,String>który reprezentuje interfejs funkcji, która przyjmuje parametr wejściowy typu T i zwraca ciąg (dane wyjściowe dla konsoli)
classPrintListToConsole<T>{privateFunc<T,String> _renderFunc;publicvoidSetRenderFunc(Func<T,String> r){// this is the point where I can set the render mechanism
_renderFunc = r;}publicvoidPrint(List<T>list){foreach(var item inlist){Console.Write(_renderFunc(item));}}}
Gdy programista używa twojego komponentu, po prostu przekazuje do komponentu implementację Func<T, String>typu, czyli funkcji, która tworzy dane wyjściowe dla konsoli.
classProgram{staticvoidMain(string[] args){varlist=newList<int>{1,2,3};// should be a list as the method signature expectsvar printer =newPrintListToConsole<int>();
printer.SetRenderFunc((o)=>"Number:"+ o);
printer.Print(list);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.
Dzięki za wysłanie tego Marco. Naprawdę mi pomogło. Od jakiegoś czasu próbuję zrozumieć func i aktywnie używać go w programowaniu. Ten przykład oczyści ścieżkę. Musiałem dodać metodę StampaFunc, ponieważ została ona pominięta w oryginalnym kodzie, co uniemożliwiło jej wyświetlenie.
Siwoku Adeola
1
Myślę, że brakuje linii w próbce Func. Gdzie jest wywołanie funkcji drukowania lub StampaFunc?
Bashar Abu Shamaa
11
Func<T1,R>i inne predefiniowane generyczne Funcdelegaci ( Func<T1,T2,R>, Func<T1,T2,T3,R>i inne) są generyczne delegaci które zwracają typ ostatniego parametru rodzajowego.
Jeśli masz funkcję, która musi zwracać różne typy, w zależności od parametrów, możesz użyć Funcdelegata, określając zwracany typ.
Jest to po prostu wstępnie zdefiniowany delegat ogólny. 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.
Func to niestandardowy delegat zdefiniowany w przestrzeni nazw System, który umożliwia wskazanie metody z tym samym podpisem (co robią delegaci), używając od 0 do 16 parametrów wejściowych i która musi coś zwrócić.
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
Odpowiedzi:
Func<T>
jest predefiniowanym typem delegata dla metody, która zwraca pewną wartość typuT
.Innymi słowy, możesz użyć tego typu, aby odwołać się do metody, która zwraca pewną wartość
T
. Na przykładmogą być określane w ten sposób
źródło
Func<T>
jestdelegate TResult Func<out TResult>()
. Żadnych argumentów.Func<T1, T2>
byłaby funkcją, która przyjmuje jeden argument.static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)Extension
atrybut, który jest odczytywany tylko przez kompilatory C # / VB.Net, a nie CLR. Zasadniczo metody instancji (w przeciwieństwie do funkcji statycznych) mają ukryty zerowy parametr „ten”. Zatem metoda instancji z 1 argumentem jest bardzo podobna do funkcji statycznej z 2 argumentami. Następnie mamy delegatów, którzy przechowują obiekt docelowy i wskaźnik funkcji . Delegaci mogą przechowywać pierwszy argument w miejscu docelowym lub tego nie robić.Potraktuj to jako symbol zastępczy. Może to być całkiem przydatne, gdy masz kod, który jest zgodny z określonym wzorcem, ale nie musi być powiązany z żadną konkretną funkcjonalnością.
Weźmy na przykład pod uwagę
Enumerable.Select
metodę rozszerzenia.Ta metoda przyjmuje
Func<T, TResult>
zamiast dowolnej konkretnej funkcji. Pozwala to na użycie go w dowolnym kontekście, w którym ma zastosowanie powyższy wzorzec.Na przykład, powiedzmy, że mam plik
List<Person>
i chcę tylko nazwiska każdej osoby na liście. Mogę to zrobić:Albo powiedz, że chcę wiek każdej osoby:
Od razu widać, jak udało mi się wykorzystać ten sam kod reprezentujący wzorzec (z
Select
) z dwiema różnymi funkcjami (p => p.Name
ip => p.Age
).Alternatywą byłoby zapisanie innej wersji za
Select
każdym razem, gdy chciałbyś przeskanować sekwencję pod kątem innego rodzaju wartości. Aby osiągnąć taki sam efekt jak powyżej, potrzebowałbym:Dzięki delegatowi pełniącemu rolę elementu zastępczego, uwalniam się od konieczności ciągłego pisania tego samego wzoru w takich przypadkach.
źródło
Func<T1, T2, ..., Tn, Tr>
reprezentuje funkcję, która przyjmuje (T1, T2, ..., Tn) argumenty i zwraca Tr.Na przykład, jeśli masz funkcję:
Możesz zapisać to jako rodzaj zmiennej funkcji:
Następnie użyj dokładnie tak, jak używałbyś sqr:
itp.
Pamiętaj jednak, że jest to delegat, więcej szczegółowych informacji znajdziesz w dokumentacji.
źródło
znajduję
Func<T>
bardzo przydatne podczas tworzenia komponentu, który wymaga personalizacji „w locie”.Weźmy ten bardzo prosty przykład: a
PrintListToConsole<T>
komponent.Bardzo prosty obiekt, który drukuje listę obiektów na konsoli. Chcesz, aby deweloper, który go używa, spersonalizował dane wyjściowe.
Na przykład chcesz pozwolić mu zdefiniować określony typ formatu liczb i tak dalej.
Bez Func
Najpierw musisz utworzyć interfejs dla klasy, która pobiera dane wejściowe i tworzy ciąg do wydrukowania na konsoli.
Następnie musisz utworzyć klasę,
PrintListToConsole<T>
która przejmuje poprzednio utworzony interfejs i używa go do każdego elementu listy.Deweloper, który musi użyć Twojego komponentu, musi:
zaimplementować interfejs
przekazać prawdziwą klasę do
PrintListToConsole
Korzystanie z Func jest znacznie prostsze
Wewnątrz komponentu definiujesz parametr typu,
Func<T,String>
który reprezentuje interfejs funkcji, która przyjmuje parametr wejściowy typu T i zwraca ciąg (dane wyjściowe dla konsoli)Gdy programista używa twojego komponentu, po prostu przekazuje do komponentu implementację
Func<T, String>
typu, czyli funkcji, która tworzy dane wyjściowe dla konsoli.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.źródło
Func<T1,R>
i inne predefiniowane generyczneFunc
delegaci (Func<T1,T2,R>
,Func<T1,T2,T3,R>
i inne) są generyczne delegaci które zwracają typ ostatniego parametru rodzajowego.Jeśli masz funkcję, która musi zwracać różne typy, w zależności od parametrów, możesz użyć
Func
delegata, określając zwracany typ.źródło
Jest to po prostu wstępnie zdefiniowany delegat ogólny. 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.źródło
Może nie jest za późno, aby dodać informacje.
Suma:
Func to niestandardowy delegat zdefiniowany w przestrzeni nazw System, który umożliwia wskazanie metody z tym samym podpisem (co robią delegaci), używając od 0 do 16 parametrów wejściowych i która musi coś zwrócić.
Nazewnictwo i sposób użycia:
Definicja:
Gdzie jest używany:
Jest używany w wyrażeniach lambda i metodach anonimowych.
źródło