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?

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.


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

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.


Ś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!");

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.


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


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


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.


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; }
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.