Usi del delegato d'azione in C # [chiuso]


132

Stavo lavorando con i delegati d'azione in C # nella speranza di saperne di più su di loro e pensare a dove potrebbero essere utili.

Qualcuno ha usato il delegato d'azione, e se sì perché? o potresti dare alcuni esempi in cui potrebbe essere utile?

Risposte:


25

MSDN dice:

Questo delegato viene utilizzato dal metodo Array.ForEach e dal metodo List.ForEach per eseguire un'azione su ciascun elemento dell'array o dell'elenco.

Tranne quello, puoi usarlo come delegato generico che accetta 1-3 parametri senza restituire alcun valore.


Non ho mai notato quelle versioni multiparametriche di Action. Grazie.
mackenir,

114

Ecco un piccolo esempio che mostra l'utilità del delegato 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);
    }
}

Si noti che il metodo foreach esegue l'iterazione della raccolta di nomi ed esegue il printmetodo su ciascun membro della raccolta. Questo è un po 'un cambio di paradigma per noi sviluppatori C # mentre ci muoviamo verso uno stile di programmazione più funzionale. (Per maggiori informazioni sull'informatica dietro di essa leggi questo: http://en.wikipedia.org/wiki/Map_(higher-order_function) .

Ora se stai usando C # 3 puoi farlo un po 'su con un'espressione lambda in questo modo:

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();
    }
}

68

Bene, una cosa che potresti fare è se hai un interruttore:

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

E con la potenza delle azioni puoi trasformare questo interruttore in un dizionario:

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

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

...

methodList[SomeEnum](someUser);

Oppure potresti andare oltre:

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

....

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

Solo un paio di esempi. Naturalmente l'uso più ovvio sarebbero i metodi di estensione Linq.


Fantastico, penso che questo potrebbe essere usato come una tabella delle decisioni.
Biswanath,

3
Bello - questo è un modello di refactoring "Sostituisci condizionale con polimorfismo". refactoring.com/catalog/replaceConditionalWithPolymorphism.html
David Robbins,

16

È possibile utilizzare le azioni per i gestori di eventi brevi:

btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");

Puoi usarli anche per quelli lunghi; btnSubmit.Click + = (mittente, e) => {MessageBox.Show ("Hai fatto clic su Salva!"); MessageBox.Show ("Davvero!"); };
tdgtyugdyugdrugdr

15

Ho usato il delegato d'azione in questo modo in un progetto una volta:

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()}
    };

il che non fa altro che archiviare un'azione (chiamata di metodo) contro un tipo di controllo in modo da poter cancellare tutti i controlli di un modulo alle impostazioni predefinite.


Bello, non un grande cambiamento, ma c'è qualcosa chiamato keyedbyTypeCollection, anche se penso che possa essere avvolto in dictioinary (type, Object).
Biswanath,

13

Per un esempio di come viene utilizzata l'azione <>.

Console.WriteLine ha una firma che soddisfa 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);         
    }

Spero che questo ti aiuti


11

Lo uso quando ho a che fare con chiamate a thread incrociati illegali Ad esempio:

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();
}));

Devo dare credito all'utente Reed Copsey SO 65358 per la soluzione. La mia domanda completa con le risposte è la domanda 2587930


3

L'ho usato come callback in un gestore eventi. Quando sollevo l'evento, passo un metodo prendendo una stringa un parametro. Ecco come si presenta l'innalzamento dell'evento:

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

Il metodo:

   public void UpdateMethod(string SpecialCode){ }

È la dichiarazione di classe dell'evento Args:

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

In questo modo posso chiamare il metodo passato dal gestore eventi con un parametro per aggiornare i dati. Lo uso per richiedere alcune informazioni all'utente.


Ciao Sorskoot, potresti espandere il modo in cui UpdateMethod, MyEventArgs e il nuovo BalieEventArgs stanno giocando insieme. è la stringa Messaggio passato in UpdateMethod: UpdateMethod ("A Message")? Quale metodo utilizza l'oggetto "someDataObject"? Grazie in anticipo
surfmuggle il

2

Usiamo molte funzionalità dei delegati di azione nei test. Quando è necessario creare un oggetto predefinito e successivamente è necessario modificarlo. Ho fatto un piccolo esempio. Per costruire un oggetto persona predefinita (John Doe) usiamo la BuildPerson()funzione. Più tardi aggiungiamo anche Jane Doe, ma modificiamo la sua data di nascita, il nome e l'altezza.

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; }
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.