Zastosowania delegata akcji w języku C # [zamknięte]

132

Pracowałem z delegatami akcji w języku C # w nadziei, że dowiem się o nich więcej i pomyśleć, gdzie mogą być przydatne.

Czy ktoś użył delegata akcji, a jeśli tak, to dlaczego? czy możesz podać kilka przykładów, w których może to być przydatne?

Biswanath
źródło

Odpowiedzi:

25

MSDN mówi:

Ten delegat jest używany przez metodę Array.ForEach i metodę List.ForEach do wykonywania akcji na każdym elemencie tablicy lub listy.

Poza tym można go używać jako delegata ogólnego, który przyjmuje 1-3 parametry bez zwracania żadnej wartości.

arul
źródło
Nigdy nie zauważyłem tych wieloparametrowych wersji Action. Dzięki.
mackenir
114

Oto mały przykład, który pokazuje przydatność delegata akcji

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

Zwróć uwagę, że metoda foreach iteruje kolekcję nazw i wykonuje printmetodę dla każdego elementu członkowskiego kolekcji. To trochę zmiana paradygmatu dla nas, programistów C #, w miarę zbliżania się do bardziej funkcjonalnego stylu programowania. (Aby uzyskać więcej informacji na temat informatyki, która się za tym kryje, przeczytaj to: http://en.wikipedia.org/wiki/Map_(higher-order_function) .

Teraz, jeśli używasz C # 3, możesz nieco poprawić to za pomocą wyrażenia lambda, takiego jak:

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
źródło
68

Cóż, jedna rzecz, którą możesz zrobić, to jeśli masz przełącznik:

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

Dzięki potędze działań możesz zmienić ten przełącznik w słownik:

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

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

...

methodList[SomeEnum](someUser);

Lub możesz pójść dalej:

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

....

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

Tylko kilka przykładów. Oczywiście bardziej oczywistym zastosowaniem byłyby metody rozszerzeń Linq.

Narzędzie Programmin
źródło
Świetnie, myślę, że można to wykorzystać jako stół decyzyjny.
Biswanath
3
Fajnie - to jest wzorzec refaktoryzacji „Zastąp warunkowy polimorfizmem”. refactoring.com/catalog/replaceConditionalWithPolymorphism.html
David Robbins,
16

Możesz użyć akcji dla krótkich programów obsługi zdarzeń:

btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");
Aaron Powell
źródło
Możesz ich używać również do długich; btnSubmit.Click + = (sender, e) => {MessageBox.Show ("Kliknąłeś, aby zapisać!"); MessageBox.Show ("Naprawdę!"); };
tdgtyugdyugdrugdr
15

Kiedyś użyłem delegata akcji w taki sposób w projekcie:

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

jedyne, co robi, to zapisywanie akcji (wywołanie metody) w odniesieniu do typu kontrolki, dzięki czemu można wyczyścić wszystkie kontrolki w formularzu z powrotem do wartości domyślnych.

Nathan W.
źródło
Fajnie, niezbyt duża zmiana, ale jest coś, co nazywa się keyedbyTypeCollection, chociaż myślę, że może to być zawijanie się wokół dictioinary (type, Object).
Biswanath,
13

Jako przykład użycia Action <>.

Console.WriteLine ma podpis, który jest satysfakcjonujący 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);         
    }

Mam nadzieję że to pomoże

Binary Worrier
źródło
11

Używam go, gdy mam do czynienia z nielegalnymi połączeniami między wątkami Na przykład:

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

Muszę przyznać uznanie użytkownikowi Reed Copsey SO 65358 za rozwiązanie. Moje pełne pytanie z odpowiedziami to pytanie SO 2587930

Ron Skufca
źródło
3

Użyłem go jako wywołania zwrotnego w programie obsługi zdarzeń. Kiedy podnoszę zdarzenie, przekazuję metodę pobierającą ciąg jako parametr. Oto jak wygląda podbicie wydarzenia:

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

Metoda:

   public void UpdateMethod(string SpecialCode){ }

Jest to deklaracja klasy zdarzenia Args:

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

W ten sposób mogę wywołać metodę przekazaną z programu obsługi zdarzeń z pewnym parametrem, aby zaktualizować dane. Używam tego, aby poprosić użytkownika o pewne informacje.

Sorskoot
źródło
Cześć Sorskoot, czy mógłbyś rozszerzyć sposób, w jaki UpdateMethod, MyEventArgs i nowe BalieEventArgs grają razem. jest ciągiem Message przekazanym do UpdateMethod: UpdateMethod ("A Message")? Która metoda używa obiektu „someDataObject”? Z góry dzięki
surfmuggle
2

W testach używamy wielu funkcji delegowania akcji. Kiedy musimy zbudować jakiś domyślny obiekt, a później musimy go zmodyfikować. Zrobiłem mały przykład. Aby zbudować domyślny obiekt osoby (John Doe), używamy BuildPerson()funkcji. Później dodajemy też Jane Doe, ale modyfikujemy jej datę urodzenia, imię i wzrost.

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; }
    }
ten zły
źródło