我知道您何时使用委托,委托的工作方式,以及可以使用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
您有一个方法,并将方法作为参数传递给它。因此,似乎您做了一些封装。但这是代表的真正好处吗?封装函数。
当然,您不必再次遍历员工列表。因为这当然较短:
private void GiveRaise(Employee employee)
{
employee.Salary *= 1.1m;
}
希望得到一些我误会的反馈。
对我来说,这似乎也像对特定对象的过滤器一样工作。因为在这种情况下,您有一个对象Employee。而且您想与该员工做一些事情。因此,提高薪水或将他们分组。
因此,最后不必重复代码了吗?这也正确吗?
在您的示例中,使用委托没有太大意义,因为所有内容都在类内(此处为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
方法并使用lambda表达式来简化此操作:
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);
对,委托的好处之一是您可以将它作为参数传递给函数,但这不是唯一的一个
您可以将委托视为可以包含功能列表的变量,可以分配
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)
我建议考虑一种非常常见的更新记录的方案。流程会像这样]
public class EmployeeRepo
{
public void Process(Employee emp)
{
/// get model
/// check if null
/// process model
/// check if mode is valid
/// save
}
}