Использование делегата действия в C # [закрыто]


132

Я работал с делегатами действий на C # в надежде узнать о них больше и подумать, где они могут быть полезны.

Кто-нибудь использовал Action Delegate, и если да, то почему? или вы могли бы привести несколько примеров, где это могло бы быть полезно?

Ответы:


25

MSDN говорит:

Этот делегат используется методами Array.ForEach и List.ForEach для выполнения действия с каждым элементом массива или списка.

Кроме того, вы можете использовать его как универсальный делегат, который принимает 1-3 параметра без возврата какого-либо значения.


Я никогда не замечал этих многопараметрических версий Action. Спасибо.
mackenir

114

Вот небольшой пример, демонстрирующий полезность делегата действия.

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

Обратите внимание, что метод foreach выполняет итерацию по коллекции имен и выполняет printметод для каждого члена коллекции. Это своего рода смена парадигмы для нас, разработчиков C #, по мере того, как мы движемся к более функциональному стилю программирования. (Для получения дополнительной информации об информатике, стоящей за этим, прочтите это: http://en.wikipedia.org/wiki/Map_(higher-order_function) .

Теперь, если вы используете C # 3, вы можете немного улучшить это с помощью лямбда-выражения, например:

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

Что ж, одну вещь вы могли бы сделать, если у вас есть переключатель:

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

И с помощью мощи действий вы можете превратить этот переключатель в словарь:

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

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

...

methodList[SomeEnum](someUser);

Или вы можете пойти дальше:

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

....

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

Еще пара примеров. Конечно, более очевидным применением будут методы расширения Linq.


Отлично, я думаю, это можно было бы использовать как таблицу решений.
Бисванат

3
Красиво - это шаблон рефакторинга «Замени условного на полиморфизм». refactoring.com/catalog/replaceConditionalWithPolymorphism.html
Дэвид Роббинс,

16

Вы можете использовать действия для коротких обработчиков событий:

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

Вы можете использовать их и для длинных; btnSubmit.Click + = (sender, e) => {MessageBox.Show («Вы нажали кнопку« Сохранить »!»); MessageBox.Show («Вы действительно сделали!»); };
tdgtyugdyugdrugdr

15

Я однажды использовал такой делегат действия в проекте:

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

все, что он делает, это сохраняет действие (вызов метода) для определенного типа управления, чтобы вы могли очистить все элементы управления в форме до значений по умолчанию.


Приятно, небольшие изменения, но есть что-то, называемое keyedbyTypeCollection, хотя я думаю, что это может быть связано с dictioinary (type, Object).
Бисванат

13

Пример использования Action <>.

Console.WriteLine имеет удовлетворительную подпись 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);         
    }

Надеюсь это поможет


11

Я использую его, когда имею дело с незаконными вызовами перекрестных потоков. Например:

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

Я должен отдать должное пользователю Reed Copsey SO 65358 за решение. Мой полный вопрос с ответами: SO Вопрос 2587930


3

Я использовал его как обратный вызов в обработчике событий. Когда я вызываю событие, я передаю метод, принимающий строку в качестве параметра. Вот как выглядит постановка ивента:

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

Метод:

   public void UpdateMethod(string SpecialCode){ }

Это объявление класса события Args:

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

Таким образом, я могу вызвать метод, переданный из обработчика событий, с некоторым параметром для обновления данных. Я использую это, чтобы запросить у пользователя некоторую информацию.


Привет, Сорскут, не могли бы вы рассказать, как UpdateMethod, MyEventArgs и новый BalieEventArgs работают вместе. строка Message передана в UpdateMethod: UpdateMethod ("A Message")? Какой метод использует объект someDataObject? Заранее спасибо
surfmuggle

2

В тестах мы используем множество функций делегирования действий. Когда нам нужно создать какой-то объект по умолчанию, а позже нужно его изменить. Я привел небольшой пример. Для создания объекта «человек по умолчанию» (Джон Доу) мы используем BuildPerson()функцию. Позже мы добавим и Джейн Доу, но изменим ее дату рождения, имя и рост.

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; }
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.