una saber programas programar programa plataformas para online moviles ibuildapp hacer gratis desde crear como cero apps app aplicaciones c# delegates action anonymous-methods func

c# - saber - programa para crear aplicaciones android



¿Cómo se usa Func<> y Action<> al diseñar aplicaciones? (9)

Al mantenerlos genéricos y admitir múltiples argumentos, nos permite evitar tener que crear delegados tipeados fuertes o delegados redundantes que hagan lo mismo.

Todos los ejemplos que puedo encontrar sobre Func <> y Action <> son simples, como en el siguiente donde se ve cómo funcionan técnicamente, pero me gustaría verlos utilizados en ejemplos donde resuelven problemas que anteriormente no podían ser resueltos o podían solucionarse. ser resuelto solo de una manera más compleja, es decir, sé cómo funcionan y puedo ver que son escuetos y poderosos , por lo que quiero entenderlos en un sentido más amplio de qué tipo de problemas resuelven y cómo podría usarlos en el diseño de aplicaciones.

¿De qué maneras (patrones) usas Func <> y Action <> para resolver problemas reales?

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestFunc8282 { class Program { static void Main(string[] args) { //func with delegate Func<string, string> convert = delegate(string s) { return s.ToUpper(); }; //func with lambda Func<string, string> convert2 = s => s.Substring(3, 10); //action Action<int,string> recordIt = (i,title) => { Console.WriteLine("--- {0}:",title); Console.WriteLine("Adding five to {0}:", i); Console.WriteLine(i + 5); }; Console.WriteLine(convert("This is the first test.")); Console.WriteLine(convert2("This is the second test.")); recordIt(5, "First one"); recordIt(3, "Second one"); Console.ReadLine(); } } }


En realidad, encontré esto en (al menos - la idea):

public static T Get<T> (string cacheKey, HttpContextBase context, Func<T> getItemCallback) where T : class { T item = Get<T>(cacheKey, context); if (item == null) { item = getItemCallback(); context.Cache.Insert(cacheKey, item); } return item; }



También son útiles para refactorizar instrucciones de cambio.

Tome el siguiente ejemplo (aunque simple):

public void Move(int distance, Direction direction) { switch (direction) { case Direction.Up : Position.Y += distance; break; case Direction.Down: Position.Y -= distance; break; case Direction.Left: Position.X -= distance; break; case Direction.Right: Position.X += distance; break; } }

Con un delegado de Acción, puede refactorizarlo de la siguiente manera:

static Something() { _directionMap = new Dictionary<Direction, Action<Position, int>> { { Direction.Up, (position, distance) => position.Y += distance }, { Direction.Down, (position, distance) => position.Y -= distance }, { Direction.Left, (position, distance) => position.X -= distance }, { Direction.Right, (position, distance) => position.X += distance }, }; } public void Move(int distance, Direction direction) { _directionMap[direction](this.Position, distance); }


Tengo un formulario separado que acepta un Func genérico o una Acción en el constructor, así como algo de texto. Ejecuta Func / Action en un hilo separado mientras visualiza un texto en el formulario y muestra una animación.

Está en mi biblioteca personal de Util, y la uso cada vez que quiero hacer una operación de longitud media y bloquear la interfaz de usuario de una manera no intrusiva.

Consideré poner una barra de progreso en el formulario también, de modo que pudiera realizar operaciones de ejecución más largas, pero aún no lo había necesitado realmente.


Una cosa para la que lo uso es el almacenamiento en caché de costosas llamadas a métodos que nunca cambian dada la misma entrada:

public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> f) { Dictionary<TArgument, TResult> values; var methodDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>(); var name = f.Method.Name; if (!methodDictionaries.TryGetValue(name, out values)) { values = new Dictionary<TArgument, TResult>(); methodDictionaries.Add(name, values); } return a => { TResult value; if (!values.TryGetValue(a, out value)) { value = f(a); values.Add(a, value); } return value; }; }

El ejemplo de fibonacci recursivo predeterminado:

class Foo { public Func<int,int> Fibonacci = (n) => { return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n; }; public Foo() { Fibonacci = Fibonacci.Memoize(); for (int i=0; i<50; i++) Console.WriteLine(Fibonacci(i)); } }


Usando linq.

List<int> list = { 1, 2, 3, 4 }; var even = list.Where(i => i % 2);

El parámetro para Where es un Func<int, bool> .

Las expresiones Lambda son una de mis partes favoritas de C #. :)


Uso los delegados Action y Func todo el tiempo. Normalmente los declaro con sintaxis lambda para ahorrar espacio y usarlos principalmente para reducir el tamaño de los métodos grandes. Al revisar mi método, a veces se destacarán los segmentos de código que son similares. En esos casos, envuelvo los segmentos de código similares en Action o Func . El uso del delegado reduce el código redundante, da una buena firma al segmento del código y puede promocionarse fácilmente a un método si es necesario.

Solía ​​escribir el código Delphi y puedes declarar una función dentro de una función. Action y Func logran este mismo comportamiento para mí en c #.

Aquí hay una muestra de controles de reposicionamiento con un delegado:

private void Form1_Load(object sender, EventArgs e) { //adjust control positions without delegate int left = 24; label1.Left = left; left += label1.Width + 24; button1.Left = left; left += button1.Width + 24; checkBox1.Left = left; left += checkBox1.Width + 24; //adjust control positions with delegate. better left = 24; Action<Control> moveLeft = c => { c.Left = left; left += c.Width + 24; }; moveLeft(label1); moveLeft(button1); moveLeft(checkBox1); }


Utilizo una Acción para encapsular de forma agradable las operaciones de la base de datos en ejecución en una transacción:

public class InTran { protected virtual string ConnString { get { return ConfigurationManager.AppSettings["YourDBConnString"]; } } public void Exec(Action<DBTransaction> a) { using (var dbTran = new DBTransaction(ConnString)) { try { a(dbTran); dbTran.Commit(); } catch { dbTran.Rollback(); throw; } } } }

Ahora para ejecutar en una transacción simplemente lo hago

new InTran().Exec(tran => ...some SQL operation...);

La clase InTran puede residir en una biblioteca común, lo que reduce la duplicación y proporciona una ubicación exclusiva para futuros ajustes de funcionalidad.