Лучшее понимание делегатов, некоторые объяснения - PullRequest
2 голосов
/ 13 октября 2019

Я знаю, когда вы используете делегатов, как они работают, и что вы можете использовать встроенные типы, такие как Action или Func для использования делагатов.

Но я думаю, что реальное значение, которое я до сих пор не понимаю'Т понять. Потому что у меня есть этот образец:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    // A method that processes an employee.
    // private delegate void EmployeeProcessor(Employee employee);

    // The employees.
    //  Employee employee;
    private List<Employee> Employees = new List<Employee>();

    private void Form1_Load(object sender, EventArgs e)
    {
        // Make some employees.
        MakeEmployees();

        // Show the employees.
        ShowEmployees();
    }

    // Add a single employee to the form's ListBox.
    private void ListEmployee(Employee employee)
    {
        employeesListBox.Items.Add(
            employee.Name + ", " +
            employee.Title + ", " +
            employee.Salary.ToString("C"));
    }

    // Do something for all employees.
    private void ProcessEmployees(Action<Employee> process)
    {
        foreach (Employee employee in Employees)
            process(employee);
    }

    // Display all employees in the form's ListBox.
    private void ShowEmployees()
    {
        employeesListBox.Items.Clear();
        ProcessEmployees(ListEmployee);
    }

    // Make some employees.
    private void MakeEmployees()
    {
        Employees.Add(new Employee()
        {
            Name = "Alice Archer",
            Title = "Programmer",
            Salary = 60000m,
        });
        Employees.Add(new Employee()
        {
            Name = "Bob Baker",
            Title = "Engineer",
            Salary = 70000m,
        });
        Employees.Add(new Employee()
        {
            Name = "Cindy Carter",
            Title = "Manager",
            Salary = 80000m,
        });
    }

    // Give a single employee a raise.
    private void GiveRaise(Employee employee)
    {
        employee.Salary *= 1.1m;
    }

    private void GiveRaise2()
    {
        foreach (var employee2 in Employees)
        {
            employee2.Salary *= 1.1m;
        }
    }

    // Give all employees a raise.
    private void giveRaisesButton_Click(object sender, EventArgs e)
    {
        GiveRaise2();// Without Delegate
        ProcessEmployees(GiveRaise); //With delegate
        ShowEmployees();
    }
}

Итак, я сделал два примера. ОДИН использует делегат. И никто не использует делегата. И затем вы должны перебрать список сотрудников.

И, конечно, это:

ProcessEmployees(GiveRaise); //With delegate

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

И, конечно, вам не нужно повторять список сотрудников. Потому что это, конечно, короче:

private void GiveRaise(Employee employee)
{
    employee.Salary *= 1.1m;
}

Надеюсь получить некоторую обратную связь, что я неправильно понимаю.

Мне также кажется, что это работает как фильтр для конкретного объекта. Потому что в этом случае у вас есть объект Employee. И вы хотите сделать некоторые вещи с этим сотрудником. Так что поднимите зарплату или сгруппируйте их вместе.

Так что в конце вам не нужно повторять код? Это тоже правильно?

Ответы [ 2 ]

2 голосов
/ 13 октября 2019

В вашем примере использование делегатов не имеет особого смысла, потому что все в классе (Form1 здесь). Они имеют больше смысла, если делегат и его потребитель находятся в разных классах, особенно в сочетании с генериками.

Допустим, у вас есть такой простой класс:

public class Calculator<T>
{
   public decimal Average(List<T> items, Func<T, decimal> getValue)
   {
        decimal sum = 0;

        foreach (var item in items)
            sum += getValue(item);

        return sum / items.Count();
   }
}

В вашем Form1 васЗатем можно создать метод

private decimal GetSalary(Employee employee)
{
    return employee.Salary;
}

и использовать его, например,

var calc = new Calculator<Employee>();
var avg = calc.Average(Employees, GetSalary);

. Или вы можете упростить это, обходясь без метода GetSalary, и использовать лямбда-выражение:

var avg = calc.Average(Employees, e => e.Salary);

Но настоящее преимущество в том, что вы можете легко использовать калькулятор с другими классами, скажем, у вас есть этот класс:

public class Product
{
    public decimal Weight { get; set; }
}

, затем вы можете сделать

var calc = new Calculator<Product>();
var avgWeight = calc.Average(listOfProducts, p => p.Weight);
1 голос
/ 13 октября 2019

Правильно, одно из преимуществ делегата состоит в том, что вы можете передать его в качестве аргумента функции, но это не единственный

Вы можете принять делегат в качестве переменной, которая может содержать список функций,Вы можете назначить

Action a = MyFunction;

Добавить новую функцию в список

a+= MyFunction1

Удалить функцию из списка

a-= MyFunction1

Вызвать все функции в списке

a();

Перебирать все функции в списке

foreach (var myHandler in a.GetInvocationList()) {
    // Call single myHandler() if you want
}

И передавать его в качестве аргумента другому методу, который может вызвать его при необходимости

Foo(a); // where Foo(Action d)
...