C#中提供了两个很有用的关键字,delegate 和 event。 那么为什么要用到这两个关键字呢?event是delegate的特许表现,那么为什么要“多此一举”?
C#中提供了两个很有用的关键字,delegate 和 event。 那么为什么要用到这两个关键字呢?event是delegate的特许表现,那么为什么要“多此一举”?
一 调用函数传递的参数
eg: int a = int.Parse("99").
很显然,这里的参数是一个字符串。通常情况下,可以给函数传递的数据类型包括系统自定义的类型和用户扩展的任何类型。那么,有没有一种可能,传递的参数是一个函数呢? 答案是肯定的。比如下面的情况:
启动线程 :在C#中,可以告诉计算机并行运行某些新的执行系列。这种系列称为线程,在基类System.Threading.Thread的一个实例上使用方法Start()。当开始新的执行系列的时候,必须的告诉计算机新开始执行系列的方法细节,既Thread.Start()方法必须带有一个参数,而这个参数包含另一个方法的内容。
调用库 :许多库包含执行各种标志任务的代码,它们在编写时,可以很容易知道任务该如何执行。但是有时,任务中还包含子任务,只有使用该库的客户代码才知道如何执行这些子任务。eg:对一个对象数组排序,类库中并不知道将是什么类型的对象,只有使用此类库的客户知道是那种类型,并知道这个对象应当如何比较。换句话讲,使用此类的客户代码必须传递可以进行这个对象比较的合适方法的细节。
事件 :GUI编程,主要是处理事件。如把许多字符键入到windows的word中,每次敲击键盘的一个键位,都需要通知word,以便word执行相应的操作。其工作方法是:每次敲击一个键,Windows就在Word中调用一个方法,执行合适的操作。用专业术语讲,就是处理事件。为了使Windows完成这个任务,Word必须通知Windows,应调用哪个方法来响应这个击键操作。所以,Word调用Windows API函数时,必须提供这个方法的细节。方法的细节又作为函数参数传递。
二 直接传递方法
前面说明了把方法细节作为参数传递给其他方法的规则,下面讨论如何实现。最直接的莫过于把方法名作为参数传递出去。eg:
void EntryPoint()
{
// Do something here.
}
Thread.Start(EntryPoint);
实际上,C和C++使用的正是这种方法,参数EntryPoint是一个函数指针。但这种很直接的方法会导致一些问题,例如类型的安全性,在进行面向对象的编程时,方法很少是孤立的,在调用前,通常需要与类实例关联。而这种方法并没有考虑到这个问题。所以,在c#中不允许直接的方法传递,如果要传递,必须把方法的细节包装在一个新类型的对象中,既委托Delegate。委托只是一种特许的对象类型,其特许在于,以前的对象都包含数据,而委托只有方法。
三 delegate的定义和实例化
delegate既然是一种对象类型,肯定也有对象类型特有的定义和实例规则,既实用之前必须定义此对象,以告诉编译器此类有什么字段和方法签名等;在使用过程中,必须实例出此类的一个对象,以便调用其方法。
delegate的定义:
delegate void VoidOperation(string x);
通过这个定义可以看出,委托在定义时,给出了方法的所有特征。
delegate的实例:
VoidOperation operation = new VoidOperation(50.ToString);
四 使用delegate的两个样例
1. 委托数组
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
namespace TestCommonConsole
{
public class MathOperator
{
public static double MultiByTwo(double d)
{
return d * 2;
}
public static double MultiBySelf(double d)
{
return d * d;
}
}
public delegate double DoubleDelegate(double d);
class Program
{
static void ProcessDelegate(DoubleDelegate action, double para)
{
double result = action(para);
Console.WriteLine("Valus is {0} Result of operation is {1}", para, result);
}
static void Main(string[] args)
{
DoubleDelegate[] delegates = {
new DoubleDelegate(MathOperator.MultiByTwo),
new DoubleDelegate(MathOperator.MultiBySelf)};
foreach (DoubleDelegate del in delegates)
{
ProcessDelegate(del, 2);
ProcessDelegate(del, 1.59);
ProcessDelegate(del, 1.414);
Console.WriteLine();
}
}
}
}
2 BubbleSort
假设要编写一个排序方法,它执行的是一个静态sort。方法的第一个参数是一个对象数组,第二个方法是一个代理方法,告诉sort函数如何对对象进行排序。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
namespace TestCommonConsole
{
public delegate bool CompareOp(object lhs, object rhs);
public class BubbleSort
{
public static void Sort(object[] array, CompareOp rhsIsGreater)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < i; j++)
{
if(rhsIsGreater(array[i], array[j]))
{
object temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
}
public class Employee
{
public string Name { get; set; }
public decimal Selary { get; set; }
public Employee(string name, decimal selary)
{
Name = name;
Selary = selary;
}
public override string ToString()
{
return string.Format(Name + ", {0:C}", Selary);
}
public static bool rhsIsGreater(object lhs, object rhs)
{
Employee l = lhs as Employee;
Employee r = rhs as Employee;
return r.Selary > l.Selary ? true : false;
}
}
class App
{
static void Main(string[] args)
{
Employee[] employees = {
new Employee("A", 10000),
new Employee("B", 3545),
new Employee("C", 15689),
new Employee("D", 1121),
new Employee("E", 134)};
for(int i=0;i<employees.Length; i++)
{
Console.WriteLine(employees[i].ToString());
}
BubbleSort.Sort(employees, Employee.rhsIsGreater);
Console.WriteLine("After sort");
for (int i = 0; i < employees.Length; i++)
{
Console.WriteLine(employees[i].ToString());
}
}
}
}