Usos del delegado de Acción en C # [cerrado]

132

Estaba trabajando con los Delegados de Acción en C # con la esperanza de aprender más sobre ellos y pensar dónde podrían ser útiles.

¿Alguien ha usado el delegado de acción? Si es así, ¿por qué? ¿O podría dar algunos ejemplos donde podría ser útil?

Biswanath
fuente

Respuestas:

25

MSDN dice:

Este delegado es utilizado por el método Array.ForEach y el método List.ForEach para realizar una acción en cada elemento de la matriz o lista.

Excepto eso, puede usarlo como un delegado genérico que toma 1-3 parámetros sin devolver ningún valor.

arul
fuente
Nunca noté esas versiones de parámetros múltiples de Action. Gracias.
mackenir
114

Aquí hay un pequeño ejemplo que muestra la utilidad del delegado de Action

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Action<String> print = new Action<String>(Program.Print);

        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(print);

        Console.Read();
    }

    static void Print(String s)
    {
        Console.WriteLine(s);
    }
}

Observe que el método foreach itera la colección de nombres y ejecuta el printmétodo contra cada miembro de la colección. Esto es un cambio de paradigma para nosotros los desarrolladores de C # a medida que avanzamos hacia un estilo de programación más funcional. (Para obtener más información sobre la informática detrás de esto, lea esto: http://en.wikipedia.org/wiki/Map_(higher-order_function) .

Ahora, si está utilizando C # 3, puede deslizar esto un poco hacia arriba con una expresión lambda como esta:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(s => Console.WriteLine(s));

        Console.Read();
    }
}
Andrew Hare
fuente
68

Bueno, una cosa que podrías hacer es si tienes un interruptor:

switch(SomeEnum)
{
  case SomeEnum.One:
      DoThings(someUser);
      break;
  case SomeEnum.Two:
      DoSomethingElse(someUser);
      break;
}

Y con el poder de las acciones, puede convertir ese interruptor en un diccionario:

Dictionary<SomeEnum, Action<User>> methodList = 
    new Dictionary<SomeEnum, Action<User>>()

methodList.Add(SomeEnum.One, DoSomething);
methodList.Add(SomeEnum.Two, DoSomethingElse); 

...

methodList[SomeEnum](someUser);

O podrías llevar esto más lejos:

SomeOtherMethod(Action<User> someMethodToUse, User someUser)
{
    someMethodToUse(someUser);
}  

....

var neededMethod = methodList[SomeEnum];
SomeOtherMethod(neededMethod, someUser);

Solo un par de ejemplos. Por supuesto, el uso más obvio serían los métodos de extensión de Linq.

Herramienta Programmin
fuente
Genial, creo que esto podría usarse como una mesa de decisión.
Biswanath
3
Agradable: este es un patrón de refactorización "Reemplazar condicional por polimorfismo". refactoring.com/catalog/replaceConditionalWithPolymorphism.html
David Robbins
16

Puede usar acciones para controladores de eventos cortos:

btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");
Aaron Powell
fuente
Puedes usarlos para los largos también; btnSubmit.Click + = (remitente, e) => {MessageBox.Show ("¡Hiciste clic en guardar!"); MessageBox.Show ("¡Realmente lo hiciste!"); };
tdgtyugdyugdrugdr
15

Usé el delegado de acción como este en un proyecto una vez:

private static Dictionary<Type, Action<Control>> controldefaults = new Dictionary<Type, Action<Control>>() { 
            {typeof(TextBox), c => ((TextBox)c).Clear()},
            {typeof(CheckBox), c => ((CheckBox)c).Checked = false},
            {typeof(ListBox), c => ((ListBox)c).Items.Clear()},
            {typeof(RadioButton), c => ((RadioButton)c).Checked = false},
            {typeof(GroupBox), c => ((GroupBox)c).Controls.ClearControls()},
            {typeof(Panel), c => ((Panel)c).Controls.ClearControls()}
    };

lo que todo lo que hace es almacenar una acción (llamada de método) contra un tipo de control para que pueda borrar todos los controles en un formulario a sus valores predeterminados.

Nathan W
fuente
Agradable, no es un gran cambio, pero hay algo llamado keyedbyTypeCollection, aunque creo que se ajusta a dictioinary (type, Object), puede ser.
Biswanath
13

Para un ejemplo de cómo se usa la Acción <>.

Console.WriteLine tiene una firma que satisface Action<string>.

    static void Main(string[] args)
    {
        string[] words = "This is as easy as it looks".Split(' ');

        // Passing WriteLine as the action
        Array.ForEach(words, Console.WriteLine);         
    }

Espero que esto ayude

Binario Worrier
fuente
11

Lo uso cuando trato con llamadas de subprocesos ilegales. Por ejemplo:

DataRow dr = GetRow();
this.Invoke(new Action(() => {
   txtFname.Text = dr["Fname"].ToString();
   txtLname.Text = dr["Lname"].ToString(); 
   txtMI.Text = dr["MI"].ToString();
   txtSSN.Text = dr["SSN"].ToString();
   txtSSN.ButtonsRight["OpenDialog"].Visible = true;
   txtSSN.ButtonsRight["ListSSN"].Visible = true;
   txtSSN.Focus();
}));

Debo dar crédito al usuario 65358 de Reed Copsey SO por la solución. Mi pregunta completa con respuestas es SO Pregunta 2587930

Ron Skufca
fuente
3

Lo usé como devolución de llamada en un controlador de eventos. Cuando levanto el evento, paso un método tomando una cadena como parámetro. Así es como se ve el evento:

SpecialRequest(this,
    new BalieEventArgs 
    { 
            Message = "A Message", 
            Action = UpdateMethod, 
            Data = someDataObject 
    });

El método:

   public void UpdateMethod(string SpecialCode){ }

La es la declaración de clase del evento Args:

public class MyEventArgs : EventArgs
    {
        public string Message;
        public object Data;
        public Action<String> Action;
    }

De esta manera puedo llamar al método pasado desde el controlador de eventos con algún parámetro para actualizar los datos. Lo uso para solicitar alguna información al usuario.

Sorskoot
fuente
Hola Sorskoot, ¿podría expandir cómo UpdateMethod, MyEventArgs y los nuevos BalieEventArgs están jugando juntos? ¿se pasa el mensaje de cadena a UpdateMethod: UpdateMethod ("A Message")? ¿Qué método usa el objeto "someDataObject"? Gracias de antemano
surfmuggle
2

Usamos mucha funcionalidad de delegado de Action en las pruebas. Cuando necesitamos construir algún objeto predeterminado y luego necesitamos modificarlo. Hice un pequeño ejemplo. Para construir el objeto persona por defecto (John Doe) utilizamos la BuildPerson()función. Más tarde también agregamos a Jane Doe, pero modificamos su fecha de nacimiento, nombre y altura.

public class Program
{
        public static void Main(string[] args)
        {
            var person1 = BuildPerson();

            Console.WriteLine(person1.Firstname);
            Console.WriteLine(person1.Lastname);
            Console.WriteLine(person1.BirthDate);
            Console.WriteLine(person1.Height);

            var person2 = BuildPerson(p =>
            {
                p.Firstname = "Jane";
                p.BirthDate = DateTime.Today;
                p.Height = 1.76;
            });

            Console.WriteLine(person2.Firstname);
            Console.WriteLine(person2.Lastname);
            Console.WriteLine(person2.BirthDate);
            Console.WriteLine(person2.Height);

            Console.Read();
        }

        public static Person BuildPerson(Action<Person> overrideAction = null)
        {
            var person = new Person()
            {
                Firstname = "John",
                Lastname = "Doe",
                BirthDate = new DateTime(2012, 2, 2)
            };

            if (overrideAction != null)
                overrideAction(person);

            return person;
        }
    }

    public class Person
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public DateTime BirthDate { get; set; }
        public double Height { get; set; }
    }
maligno
fuente