In C# wir etwas tun, wie folgt aus:
class Program {
static Action Curry<T>(Action<T> action, T parameter) {
return() => action(parameter);
}
static void Foo(int i) {
Console.WriteLine("Value: {0}", i);
}
static void Main(string[] args) {
Action curried = Curry(Foo, 5);
curried();
}
}
Klar, dass die Methode Foo
auf Ihre Methode entspricht Foo
, nur mit den entsprechenden Anrufe zu Console.WriteLine
statt std::cout
.
Als nächstes deklarieren wir eine Methode Curry
, die eine Action<T>
akzeptiert und eine Action
zurückgibt. Im Allgemeinen ist Action<T>
ein Delegat, der einen einzelnen Parameter vom Typ T
akzeptiert und void
zurückgibt. Insbesondere ist Foo
ein Action<int>
, weil es einen Parameter des Typs int
akzeptiert und void
zurückgibt. Wie für den Rückgabetyp Curry
wird es als Action
deklariert. Ein Action
ist ein Delegat, der keine Parameter hat und void
zurückgibt.
Die Definition von Curry
ist ziemlich interessant. Wir definieren eine Aktion mit einem Lambda-Ausdruck, der eine ganz besondere Form eines anonymen Delegierten darstellt. Effektiv
() => action(parameter)
sagt, dass die void
Parameter action
bei parameter
ausgewertet abgebildet wird.
schließlich in Main
wir deklarieren eine Instanz von Action
curried
benannt, das Ergebnis ist Curry
zu Foo
mit dem Parameter 5
Anwendung. Dies spielt die gleiche Rolle wie bind(fun_ptr(foo), 5)
in Ihrem C++ Beispiel.
Zuletzt rufen wir den neu gebildeten Delegaten curried
über die Syntax curried()
auf. Dies ist wie someCallback()
in Ihrem Beispiel.
Die phantastische Bezeichnung dafür ist currying.
Als ein interessantes Beispiel, sollten Sie Folgendes beachten:
class Program {
static Func<TArg, TResult> Curry<TArg, TResult>(
Func<TArg, TArg, TResult> func,
TArg arg1
) {
return arg => func(arg1, arg);
}
static int Add(int x, int y) {
return x + y;
}
static void Main(string[] args) {
Func<int, int> addFive = Curry<int, int>(Add, 5);
Console.WriteLine(addFive(7));
}
}
Hier stellen wir ein Verfahren Curry
deklarieren, die einen Delegierten akzeptiert (Func<TArg, TArg, TResult>
, die zwei Parameter des gleichen Typs akzeptiert TArg
und gibt einen Wert von einem anderen Typ TResult
und einen Parameter vom Typ TArg
und gibt einen Vertreter, die einen einzelnen Parameter des Typs TResult
TArg
und gibt einen Wert des Typs akzeptiert (Func<TArg, TResult>
).
Als Test deklarieren wir dann eine Methode Add
, die zwei Parameter vom Typ int
akzeptiert und einen Parameter vom Typ int
(a Func<int, int, int>
) zurückgibt. Dann in Main
instanziieren wir einen neuen Delegaten mit dem Namen addFive
, der wie eine Methode wirkt, die seinem Eingabeparameter fünf hinzufügt. Also
Console.WriteLine(addFive(7));
druckt 12
auf der Konsole.
Danke für Ihre ausführliche Antwort. Ich habe das andere als die akzeptierte Antwort markiert, weil es prägnanter ist, obwohl es einige wichtige Details fehlen, die Ihre eingeschlossen haben. – Catskul
Sicher. Ich hoffe nur, dass die zusätzliche Farbe hilft. :-) – jason
Extrem nützliche Antwort, das. Einführung eines brillanten Konzepts, Currys, auf leicht verständliche Art und Weise. Wird dies definitiv zu meiner mentalen Toolbox hinzufügen. –