更好地理解代表,一些解释
Better understanding of delegates, some explanation
我知道您何时使用委托,它们是如何工作的,并且您可以使用 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();
}
}
所以我举了两个例子。 ONe 正在使用委托。一个是没有使用代表。然后你必须迭代列表 Employees.
当然还有这个:
ProcessEmployees(GiveRaise); //With delegate
你有一个方法并将方法作为参数传递给它。所以看起来你做了一些封装。但这是代表的真正好处吗?你封装函数。
当然,您不必再次迭代 Employees 列表。因为这当然更短了:
private void GiveRaise(Employee employee)
{
employee.Salary *= 1.1m;
}
希望得到一些反馈我的误解。
对我来说,它似乎也像特定对象的过滤器一样工作。因为在这种情况下,您有一个对象 Employee。你想和那个员工一起做一些事情。所以加薪或者组队。
所以最后你不必重复代码?这也对吗?
是的,delegate 的好处之一是你可以将它作为参数传递给函数,但这不是唯一的
你可以假设委托是一个可以包含函数列表的变量,你可以赋值
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)
在您的示例中,使用委托没有太大意义,因为所有内容都在 class 内(此处为 Form1
)。如果委托及其使用者处于不同的 class 中,尤其是与泛型结合使用时,它们更有意义。
假设你有这个简单的 class:
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
方法并使用 lambda 表达式来简化此操作:
var avg = calc.Average(Employees, e => e.Salary);
但现在真正的好处是您可以轻松地将您的计算器与其他 classes 重用,假设您有这个 class:
public class Product
{
public decimal Weight { get; set; }
}
然后你可以做
var calc = new Calculator<Product>();
var avgWeight = calc.Average(listOfProducts, p => p.Weight);
我知道您何时使用委托,它们是如何工作的,并且您可以使用 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();
}
}
所以我举了两个例子。 ONe 正在使用委托。一个是没有使用代表。然后你必须迭代列表 Employees.
当然还有这个:
ProcessEmployees(GiveRaise); //With delegate
你有一个方法并将方法作为参数传递给它。所以看起来你做了一些封装。但这是代表的真正好处吗?你封装函数。
当然,您不必再次迭代 Employees 列表。因为这当然更短了:
private void GiveRaise(Employee employee)
{
employee.Salary *= 1.1m;
}
希望得到一些反馈我的误解。
对我来说,它似乎也像特定对象的过滤器一样工作。因为在这种情况下,您有一个对象 Employee。你想和那个员工一起做一些事情。所以加薪或者组队。
所以最后你不必重复代码?这也对吗?
是的,delegate 的好处之一是你可以将它作为参数传递给函数,但这不是唯一的
你可以假设委托是一个可以包含函数列表的变量,你可以赋值
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)
在您的示例中,使用委托没有太大意义,因为所有内容都在 class 内(此处为 Form1
)。如果委托及其使用者处于不同的 class 中,尤其是与泛型结合使用时,它们更有意义。
假设你有这个简单的 class:
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
方法并使用 lambda 表达式来简化此操作:
var avg = calc.Average(Employees, e => e.Salary);
但现在真正的好处是您可以轻松地将您的计算器与其他 classes 重用,假设您有这个 class:
public class Product
{
public decimal Weight { get; set; }
}
然后你可以做
var calc = new Calculator<Product>();
var avgWeight = calc.Average(listOfProducts, p => p.Weight);