详解C#委托

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

1 委托

当要把方法传递给其他方法时,需要使用委托。有时候某个方法执行的操作并不是针对数据进行的,而是要对另一个方法进行操作。但是编译的时候,我们不知道第二个方法是什么,这个信息只有在运行时得到,所以需要我们把第二个方法作为参数传递给第一个方法。总之,委托就是参数为方法的函数。

事件——一般是通知代码发生了什么事件。引发了事件时,运行库需要知道应该执行哪个方法。这就要把处理事件的方法作为一个参数传递给委托。

1.1 声明委托

首先必须定义要使用的委托,对于委托,定义它就是告诉编译器这种类型的委托表示哪种类型的方法,然后必须创建该委托的一个或者多个实例。编译器在后台将创建表示该委托的一个类。语法如下:

delegate void IntMethodInvoker(int x);

在这个实例中,定义了一个委托IntMethodInvoker,并指定该委托的每个实例都可以包含一个方法的引用,该方法含有一个int参数,返回void。定义一个委托,必须给出它所表示的方法的签名和返回类型。定义委托的语法类似方法的定义,但是没有方法体,定义的前面要加上关键字delegate。可以在委托的定义上应用常用的访问修饰符:public、PRivate、protected等。

定义委托实际上是定义一个新类。委托实现为派生自基类System.MulticastDelegate的类,System.MulticastDelegate又派生自基类System.Delegate。C#编译器能识别这个类自动使用其委托语法,我们不需要了解这个类的具体执行情况。

定义好委托后就可以创建它的一个实例,但创建的委托的实例仍然称为委托。

1.2 使用委托

下面代码说明如何使用委托,这是在int上调用ToString()方法的一种冗长方式。

privatedelegatestringGetAString();//定义委托,表示的方法不带参数,返回一个string型的值。staticvoidMain()

{intx=40;

GetAString firstStringMethod=newGetAString(x.TOString);//实例化类型为GetAString的委托,并对它进行初始化,//使它引用整形变量x的ToString()方法。在C#中,委托在语法上总是接受一个参数的构造函数,这个参数就是委托引用的方法。//这个方法必须匹配最初定义委托时的签名。Console.WriteLine("String is {0}",firstStringMethod());//使用委托显示字符串//在任何代码中,都应该提供委托实例的名称,这里例子实例名称为firstStringMethod,后面括号中应该包含调用委托中方法时使用的任何等效参数}

在C#编译时,编译器会用firstString.Method.Invoke()代替firstStringMethod()。(这是IDE内部实现的,不需要编程者关心,这里只是说明下它的原理。)

为了减少代码,只需要委托实例,就可以只传送地址的名称,这称为委托推断。举例如下:

GetAString firstStringMethod =new GetAString(x.ToString);//正常用法

GetAString firstStringMethod=x.ToString;//委托推断的用法

注意:千万不能输入x.ToString()。因为加()的方法是返回一个字符串对象,不加括号代表方法地址,委托调用的是方法地址。

委托的类型是安全的,可以保证被调用的方法签名正确。

1.3 Action<T>和Func<T>委托

以上都是为参数和返回类型定义一个新委托。下面介绍Action<T>委托,泛型Action<T>委托表示引用一个void返回类型方法。Func<T>委托可以调用带返回类型的方法。Func<out TResult>委托类型可以调用带返回类型且无参数的方法,Func<int T,out TResult>调用一个带参数的方法。

举例声明一个该委托类型的数组:

Func<double ,double>[]Operations=

{

类名.方法名,类名.方法名

}

1.4 一个委托的例子:类的冒泡法排序

classBubbleSorter

{staticpublicvoidSort<T>(IList<T> sortArray,Func<T,T,bool>comparison)//接受类型T的泛型方法Sort<T>{boolswapped=true;do{

swapped=false;for(inti=0;i<sortArray.Count-1;i++)

{if(comparison(sortArray[i+1],sortArray[i]))

{

T temp=sortArray[i];

sortArray[i]=sortArray[i+1];

sortArray[i+1]=temp;

swapped=true;

}

}

}while(swapped);

}

}classEmployee

{publicEmployee(stringname,decimalsalary)

{this.Name=name;this.Salary=salary;

}publicstringName{get;privateset;}publicdecimalSalary{get;privateset;}publicstaticboolCompareSalary(Employee e1,Employee e2)

{returne1.Salary<e2.Salary;

}

}

Main函数调用时:

staticvoidMain()

{

Employee[] employees={newEmployee("Buges",2000),newEmployee("Daffy",1000),newEmployee("Foge",2300),newEmployee("Tows",5000),newEmployee("Gay",2100)

};

BubbleSorter.Sort(employees,Employee.ConpareSalary);//调用类的静态方法}

1.5多播委托

委托可以包含多个方法,那就是多播委托。为此委托的签名必须返回void;否则就只能得到委托调用的最后一个方法的结果。多播委托可以识别运算符”+“和”+=“。

Action<double>operation1=类名1.方法名1;

Action<double>operation2=类名2.方法名2;

Action<double>operationS=operation1+operation2;

多播委托可以用”-“和”-=“以从委托中删除方法调用。

多播委托派生自System.MulticastDelegate的类,System.MulticastDelegate又派生自基类System.Delegate。MulticastDelegate的其他成员允许把多个方法调用链接成一个列表。

多播委托要避免依赖于特定顺序的代码。

如果通过委托调用其中一个方法抛出异常,整个迭代就停止了。为了避免这个问题,Delegate类定义了GetInvocationList()方法,它返回一个Delegate对象数组。先中科院使用这个委托调用与委托直接相关的方法,捕获异常并继续下一次迭代。

Action d1=One;

d1+=Two;

Delegate[] delegates=d1.GetInvocationList();foreach(Action dindelegates)

{try{

d();

}catch(Exception)

{

Console.WriteLine("Exception caught");

}

}

1.6 Lambda表达式

只要有委托参数类型的地方,就可以使用Lambda表达式。签名使用匿名方法的例子可以改为使用Lambda表达式。Lambda运算符”=>“的左边列出了需要的参数。Lambda运算符右边定义了赋予lambda变量的方法的实现代码。

Func<string,string>oneParam=s=>String.Format("change uppercase{0}",s.ToUpper());

Console.WriteLine(oneParam("test"));

1.6.1 参数

Func<double,double,double>twoParamsWithTypes=(doublex,doubley)=>x*y;

Console.WriteLine(twoParamsWithTypes(4,2));

1.6.2 多行代码

Func<double,double>square=x=>x*x;

等价于

Func<double,double>square=x=>{returnx*x;

}

添加多行语句要有括号和return语句

Func<string,string>lambda=param=>{

param+=mid;

param+="and this was added to the string.";returnparam;

}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航