Dies ist nur eine Verknüpfung für Delegierte mit einer bestimmten Signatur. Um die Antworten unten vollständig zu verstehen, müssen Sie die Delegierten verstehen ;-)
Theo Lenndorff
2
In der Antwort von @Oded heißt esIf 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
Antworten:
76
Func<T>ist ein vordefinierter Delegatentyp für eine Methode, die einen Wert des Typs zurückgibt T.
Mit anderen Worten, Sie können diesen Typ verwenden, um auf eine Methode zu verweisen, die einen Wert von zurückgibt T. Z.B
Es kann aber auch eine statische Ein-Argument-Funktion darstellen =)
Ark-kun
2
@ Ark-Kun Nein, das ist nicht richtig. Die Definition von Func<T>ist delegate TResult Func<out TResult>(). Keine Argumente. Func<T1, T2>wäre eine Funktion, die ein Argument akzeptiert.
Brian Rasmussen
4
Nein, ich habe recht. static int OneArgFunc(this string i) { return 42; }Func<int> f = "foo".OneArgFunc;. =)
Ark-Kun
1
Das ist eine spezielle Erweiterungsmethode.
Brian Rasmussen
Das einzig Besondere daran ist das ExtensionAttribut, das nur von den C # / VB.Net-Compilern gelesen wird, nicht von CLR. Grundsätzlich haben Instanzmethoden (im Gegensatz zu statischen Funktionen) einen versteckten 0. "this" -Parameter. Die Instanzmethode mit 1 Argument ist der statischen Funktion mit 2 Argumenten sehr ähnlich. Dann haben wir Delegaten, die das Zielobjekt und den Funktionszeiger speichern . Delegierte können das erste Argument im Ziel speichern oder dies nicht tun.
Ark-Kun
86
Betrachten Sie es als Platzhalter. Dies kann sehr nützlich sein, wenn Sie Code haben, der einem bestimmten Muster folgt, aber nicht an eine bestimmte Funktionalität gebunden sein muss.
Betrachten Sie beispielsweise die Enumerable.SelectErweiterungsmethode.
Das Muster lautet: Wählen Sie für jedes Element in einer Sequenz einen Wert aus diesem Element aus (z. B. eine Eigenschaft) und erstellen Sie eine neue Sequenz, die aus diesen Werten besteht.
Der Platzhalter ist: eine Auswahlfunktion, die tatsächlich die Werte für die oben beschriebene Sequenz erhält.
Diese Methode übernimmt eine Func<T, TResult>anstelle einer konkreten Funktion. Dies ermöglicht die Verwendung in jedem Kontext, in dem das obige Muster gilt.
Nehmen wir zum Beispiel an, ich habe eine List<Person>und möchte nur den Namen jeder Person in der Liste. Ich kann dies tun:
var names = people.Select(p => p.Name);
Oder sagen Sie, ich möchte das Alter jeder Person:
var ages = people.Select(p => p.Age);
Sie können sofort sehen, wie ich denselben Code nutzen konnte, der ein Muster (mit Select) mit zwei verschiedenen Funktionen ( p => p.Nameund p => p.Age) darstellt.
Die Alternative wäre, Selectjedes Mal, wenn Sie eine Sequenz nach einem anderen Wert durchsuchen möchten, eine andere Version zu schreiben . Um den gleichen Effekt wie oben zu erzielen, würde ich Folgendes benötigen:
// 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);
Mit einem Delegierten als Platzhalter muss ich in solchen Fällen nicht immer wieder dasselbe Muster aufschreiben.
Hervorragende Antwort, aber zum Kompilieren von Schlüsselwörtern ist statisch erforderlich
Boctulus
16
Ich finde es Func<T>sehr nützlich, wenn ich eine Komponente erstelle, die "on the fly" personalisiert werden muss.
Nehmen Sie dieses sehr einfache Beispiel: eine PrintListToConsole<T>Komponente.
Ein sehr einfaches Objekt, das diese Liste von Objekten auf der Konsole druckt. Sie möchten, dass der Entwickler, der es verwendet, die Ausgabe personalisiert.
Sie möchten ihn beispielsweise eine bestimmte Art von Zahlenformat definieren lassen und so weiter.
Ohne Func
Zuerst müssen Sie eine Schnittstelle für eine Klasse erstellen, die die Eingabe übernimmt und die Zeichenfolge erzeugt, die auf der Konsole gedruckt werden soll.
Anschließend müssen Sie die Klasse erstellen PrintListToConsole<T>, die die zuvor erstellte Schnittstelle für jedes Element der Liste verwendet.
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));}}}
Der Entwickler, der Ihre Komponente verwenden muss, muss:
Implementieren Sie die Schnittstelle
Übergeben Sie die echte Klasse an die PrintListToConsole
Innerhalb der Komponente definieren Sie einen Parameter vom Typ Func<T,String>, der eine Schnittstelle einer Funktion darstellt , die einen Eingabeparameter vom Typ T verwendet und eine Zeichenfolge zurückgibt (die Ausgabe für die Konsole).
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));}}}
Wenn der Entwickler Ihre Komponente verwendet, übergibt er einfach die Implementierung des Func<T, String>Typs an die Komponente. Dies ist eine Funktion, die die Ausgabe für die Konsole erstellt.
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>Mit dieser Option können Sie im laufenden Betrieb eine generische Methodenschnittstelle definieren.
Sie definieren, welcher Typ die Eingabe ist und welcher Typ die Ausgabe ist. Einfach und prägnant.
Danke, dass du diesen Marco gepostet hast. Es hat mir wirklich geholfen. Ich habe eine Weile versucht, func zu verstehen und es auch aktiv in meiner Programmierung zu verwenden. In diesem Beispiel wird der Pfad gelöscht. Ich musste die StampaFunc-Methode hinzufügen, da diese im ursprünglichen Code weggelassen wurde, wodurch die Anzeige verhindert wurde.
Siwoku Adeola
1
Ich denke, im Func-Beispiel fehlt eine Zeile. Wo ist der Aufruf für die Druckfunktion oder StampaFunc?
Bashar Abu Shamaa
11
Func<T1,R>und die anderen vordefinierte generischen FuncTeilnehmer ( Func<T1,T2,R>, Func<T1,T2,T3,R>und anderen) sind generische Teilnehmer, die die Art des letzten generischen Parameters zurück.
Wenn Sie eine Funktion haben, die abhängig von den Parametern unterschiedliche Typen zurückgeben muss, können Sie einen FuncDelegaten verwenden, der den Rückgabetyp angibt.
Es ist nur ein vordefinierter generischer Delegat. Damit müssen Sie nicht jeden Delegaten deklarieren. Es gibt einen anderen vordefinierten Delegaten, Action<T, T2...>der derselbe ist, aber ungültig zurückgibt.
Vielleicht ist es nicht zu spät, um Informationen hinzuzufügen.
Summe:
Der Func ist ein benutzerdefinierter Delegat, der im System-Namespace definiert ist und es Ihnen ermöglicht, mit 0 bis 16 Eingabeparametern auf eine Methode mit derselben Signatur zu verweisen (wie dies bei Delegaten der Fall ist), die etwas zurückgeben muss.
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.
Antworten:
Func<T>
ist ein vordefinierter Delegatentyp für eine Methode, die einen Wert des Typs zurückgibtT
.Mit anderen Worten, Sie können diesen Typ verwenden, um auf eine Methode zu verweisen, die einen Wert von zurückgibt
T
. Z.Bkann so referenziert werden
quelle
Func<T>
istdelegate TResult Func<out TResult>()
. Keine Argumente.Func<T1, T2>
wäre eine Funktion, die ein Argument akzeptiert.static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)Extension
Attribut, das nur von den C # / VB.Net-Compilern gelesen wird, nicht von CLR. Grundsätzlich haben Instanzmethoden (im Gegensatz zu statischen Funktionen) einen versteckten 0. "this" -Parameter. Die Instanzmethode mit 1 Argument ist der statischen Funktion mit 2 Argumenten sehr ähnlich. Dann haben wir Delegaten, die das Zielobjekt und den Funktionszeiger speichern . Delegierte können das erste Argument im Ziel speichern oder dies nicht tun.Betrachten Sie es als Platzhalter. Dies kann sehr nützlich sein, wenn Sie Code haben, der einem bestimmten Muster folgt, aber nicht an eine bestimmte Funktionalität gebunden sein muss.
Betrachten Sie beispielsweise die
Enumerable.Select
Erweiterungsmethode.Diese Methode übernimmt eine
Func<T, TResult>
anstelle einer konkreten Funktion. Dies ermöglicht die Verwendung in jedem Kontext, in dem das obige Muster gilt.Nehmen wir zum Beispiel an, ich habe eine
List<Person>
und möchte nur den Namen jeder Person in der Liste. Ich kann dies tun:Oder sagen Sie, ich möchte das Alter jeder Person:
Sie können sofort sehen, wie ich denselben Code nutzen konnte, der ein Muster (mit
Select
) mit zwei verschiedenen Funktionen (p => p.Name
undp => p.Age
) darstellt.Die Alternative wäre,
Select
jedes Mal, wenn Sie eine Sequenz nach einem anderen Wert durchsuchen möchten, eine andere Version zu schreiben . Um den gleichen Effekt wie oben zu erzielen, würde ich Folgendes benötigen:Mit einem Delegierten als Platzhalter muss ich in solchen Fällen nicht immer wieder dasselbe Muster aufschreiben.
quelle
Func<T1, T2, ..., Tn, Tr>
stellt eine Funktion dar, die (T1, T2, ..., Tn) Argumente akzeptiert und Tr zurückgibt.Zum Beispiel, wenn Sie eine Funktion haben:
Sie könnten es als eine Art Funktionsvariable speichern:
Und dann genau so verwenden, wie Sie sqr verwenden würden:
etc.
Denken Sie jedoch daran, dass es sich um einen Delegaten handelt. Weitere Informationen finden Sie in der Dokumentation.
quelle
Ich finde es
Func<T>
sehr nützlich, wenn ich eine Komponente erstelle, die "on the fly" personalisiert werden muss.Nehmen Sie dieses sehr einfache Beispiel: eine
PrintListToConsole<T>
Komponente.Ein sehr einfaches Objekt, das diese Liste von Objekten auf der Konsole druckt. Sie möchten, dass der Entwickler, der es verwendet, die Ausgabe personalisiert.
Sie möchten ihn beispielsweise eine bestimmte Art von Zahlenformat definieren lassen und so weiter.
Ohne Func
Zuerst müssen Sie eine Schnittstelle für eine Klasse erstellen, die die Eingabe übernimmt und die Zeichenfolge erzeugt, die auf der Konsole gedruckt werden soll.
Anschließend müssen Sie die Klasse erstellen
PrintListToConsole<T>
, die die zuvor erstellte Schnittstelle für jedes Element der Liste verwendet.Der Entwickler, der Ihre Komponente verwenden muss, muss:
Implementieren Sie die Schnittstelle
Übergeben Sie die echte Klasse an die
PrintListToConsole
Mit Func ist es viel einfacher
Innerhalb der Komponente definieren Sie einen Parameter vom Typ
Func<T,String>
, der eine Schnittstelle einer Funktion darstellt , die einen Eingabeparameter vom Typ T verwendet und eine Zeichenfolge zurückgibt (die Ausgabe für die Konsole).Wenn der Entwickler Ihre Komponente verwendet, übergibt er einfach die Implementierung des
Func<T, String>
Typs an die Komponente. Dies ist eine Funktion, die die Ausgabe für die Konsole erstellt.Func<T>
Mit dieser Option können Sie im laufenden Betrieb eine generische Methodenschnittstelle definieren. Sie definieren, welcher Typ die Eingabe ist und welcher Typ die Ausgabe ist. Einfach und prägnant.quelle
Func<T1,R>
und die anderen vordefinierte generischenFunc
Teilnehmer (Func<T1,T2,R>
,Func<T1,T2,T3,R>
und anderen) sind generische Teilnehmer, die die Art des letzten generischen Parameters zurück.Wenn Sie eine Funktion haben, die abhängig von den Parametern unterschiedliche Typen zurückgeben muss, können Sie einen
Func
Delegaten verwenden, der den Rückgabetyp angibt.quelle
Es ist nur ein vordefinierter generischer Delegat. Damit müssen Sie nicht jeden Delegaten deklarieren. Es gibt einen anderen vordefinierten Delegaten,
Action<T, T2...>
der derselbe ist, aber ungültig zurückgibt.quelle
Vielleicht ist es nicht zu spät, um Informationen hinzuzufügen.
Summe:
Der Func ist ein benutzerdefinierter Delegat, der im System-Namespace definiert ist und es Ihnen ermöglicht, mit 0 bis 16 Eingabeparametern auf eine Methode mit derselben Signatur zu verweisen (wie dies bei Delegaten der Fall ist), die etwas zurückgeben muss.
Nomenklatur & how2use:
Definition:
Wo es verwendet wird:
Es wird in Lambda-Ausdrücken und anonymen Methoden verwendet.
quelle