作为.net的一个重要机制,委托的应用是非常广泛的(比如说事件,线程等等)。下面我们就委托说下自己的意见,希望各位大大能给予补充,如有不正确能予以指教,谢谢!!
什么是委托
委托是安全的回调函数,是类型安全的函数指针。
委托是一种特殊的对象类型,它的特殊之处在于,我们以前定义的所有对象都包含数据,而委托包含的只是方法的地址。
如何使用委托
在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。(定义一个委托=定义一个新类)
如:
{
private delegate string GetAString(); //声明一个委托
static void Main(string[] args)
{
int x=40;
GetAString firstStringmethods = new GetAString(x.ToString);
//GetAString firstStringmethods = x.ToString; //运用了委托推断机制
Console.WriteLine(firstStringmethods());
//Console.WriteLine(x.ToString());
Console.ReadKey();
}
}
关于委托的声明:
private delegate string GetAString();
声明了一个委托,意义:任何一个返回值为string,且不带参数的函数,都可以用这个委托来调用。
理解委托的一种好方式是把委托当做给方法签名和返回类型指定名称。
委托的声明非常类似于函数,但不带函数体,且要使用delegate关键字。
委托的声明指定了一个函数签名,其中包含一个返回类型和参数列表。
由于“定义一个委托=定义一个新类”,可以在定义类的任何地方定义委托,既可以在类的内部定义委托,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。根据定义的可见性,可以在委托定义上添加一般的访问修饰符: public、private、protected。
使用委托
给定委托的实例可以表示任何类型的任何对象上的实例方法或静态方法--只要方法的签名匹配于委托的签名即可。
GetAString firstStringmethods = new GetAString(x.ToString);
c#中,委托在语法上总是带有一个参数的构造函数,这个参数就是委托引用的方法。注意:该参数只为方法名,而不能是方法。
注意:GetAString firstStringmethods = new GetAString(x.ToString());-----是错误的
不能调用x.Tostring()方法,把它传给委托变量。调用x.Tostring()方法会返回一个不能赋予委托变量的字符串对象,产生一个编译错误。只能把方法的地址赋予委托变量。
GetAString firstStringmethods = x.ToString; //运用了委托推断机制
等同于
GetAString firstStringmethods = new GetAString(x.ToString);
都是对委托的实例化。只不过应用了委托推断机制。
为了减少输入量,只要需要委托实例,就可以只传送地址的名称,这就称为委托推断。只要编译器可以把委托实例解析为特定的类型,这个c#特性就是有效的。如上,编译器会用firstStringmethods 检测需要的委托类型,因此创建GetAString委托的一个实例,用对象x把方法的地址传送给构造函数。
委托推断可以在需要委托实例的任何地方使用。委托推断也可以用于事件,因为事件基于委托。
委托的补充
委托作为一种特殊的对象类型,也具有一般类所具有的特征:如定义实例数组,作为函数参数等等)
如:
class Program
{
private delegate double DoubleOP(double x);
static void Main(string[] args)
{
//委托数组
DoubleOP[] operation =
{
MathsOpration .MutiplybyTwo ,
MathsOpration .Square
};
for (int i = 0; i < operation.Length; i++)
{
Console.WriteLine("Using opertion[{0}]", i);
ProcessAndDisplay(operation[i], 2.0);
ProcessAndDisplay(operation[i], 7.9);
ProcessAndDisplay(operation[i], 1.414);
}
Console.ReadKey();
}
static void ProcessAndDisplay(DoubleOP action, double value)
{
double result = action(value);
Console.WriteLine("Value is {0},result of operation is {1}", value, result);
}
}
class MathsOpration
{
public static double MutiplybyTwo(double value)
{
return value * 2;
}
public static double Square(double value)
{
return value * value;
}
}
为什么要使用委托
使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。
另外,你可以尝试着编写一段对象的冒泡排序法,或许你会发现:没有委托,很多工作会很繁冗,甚至无法实现。
冒泡排序法,代码如下:
delegate bool Comparison(object x,object y);
class Program
{
static void Main(string[] args)
{
Employee[] employees =
{
new Employee ("aa",1000),
new Employee ("ss",5000),
new Employee ("dd",52222),
new Employee ("ff",8000),
new Employee ("gg",6666)
};
BubbleSort.Sort(employees, Employee.CompareSalary);
foreach (Employee e in employees)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
}
class BubbleSort
{
static public void Sort(object[] sortArray, Comparison comparison)
{
for (int i = 0; i < sortArray.Length; i++)
{
for (int j = i + 1; j < sortArray.Length; j++)
{
if (comparison(sortArray[j], sortArray[i]))
{
object temp = sortArray[i];
sortArray[i] = sortArray[j];
sortArray[j] = temp;
}
}
}
}
}
class Employee
{
private string name;
private decimal salary;
public Employee(string name, decimal salary)
{
this.name = name;
this.salary = salary;
}
public static bool CompareSalary(object x, object y)
{
Employee e1 = (Employee)x;
Employee e2 = (Employee)y;
return (e1.salary < e2.salary);
}
public override string ToString()
{
return string.Format("{0},{1:c}", name, salary);
}
}