En C# que hacer algo como esto:
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();
}
}
Es evidente que el método Foo
corresponde a su método de Foo
, sólo con las llamadas apropiadas a Console.WriteLine
en lugar de std::cout
.
A continuación, declaramos un método Curry
que acepta un Action<T>
y devuelve un Action
. En general, un Action<T>
es un delegado que acepta un único parámetro del tipo T
y devuelve void
. En particular, Foo
es un Action<int>
porque acepta un parámetro del tipo int
y devuelve void
. En cuanto al tipo de devolución de Curry
, se declara como Action
. Un Action
es un delegado que no tiene parámetros y devuelve void
.
La definición de Curry
es bastante interesante. Estamos definiendo una acción usando una expresión lambda que es una forma muy especial de un delegado anónimo. Efectivamente
() => action(parameter)
dice que el parámetro void
se asigna a action
evaluada en parameter
.
Por último, en Main
estamos declarando una instancia de Action
llamado curried
que es el resultado de aplicar a Curry
Foo
con el parámetro 5
. Esto juega el mismo rol que bind(fun_ptr(foo), 5)
en su ejemplo de C++.
Por último, invocamos al delegado recién formado curried
mediante la sintaxis curried()
. Esto es como someCallback()
en su ejemplo.
El término sofisticado para esto es currying.
Como un ejemplo más interesante, tenga en cuenta lo siguiente:
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));
}
}
Aquí estamos declarando un método Curry
que acepta un delegado (Func<TArg, TArg, TResult>
que acepta dos parámetros del mismo tipo TArg
y devuelve un valor de algún otro escriba TResult
y un parámetro de tipo TArg
y devuelve un delegado que acepta un único parámetro de tipo TArg
y devuelve un valor de tipo TResult
(Func<TArg, TResult>
).
Luego, como prueba declaramos un método Add
que acepta dos parámetros del tipo int
y devuelve un parámetro del tipo int
(a Func<int, int, int>
). Luego, en Main
instanciamos un nuevo delegado llamado addFive
que actúa como un método que agrega cinco a su parámetro de entrada. Por lo tanto,
Console.WriteLine(addFive(7));
imprime 12
en la consola.
Gracias por su respuesta detallada. Marqué el otro como la respuesta aceptada porque es más conciso, aunque le faltan algunos detalles importantes que el suyo incluyó. – Catskul
Claro. Solo espero que el color extra te ayude. :-) – jason
Respuesta extremadamente útil, esto. Introdujo un concepto brillante, currying, de una manera fácil de entender. Definitivamente agregaré esto a mi caja de herramientas mental. –