正在学习委托和事件,这次下决心把这个搞懂搞全,会慢慢更新
1.事件
一般是通知代码发生了什么事件。GUI编程主要是处理事件。在发生事件时,运行库需要知道应执行哪个方法。这就需要把处理事件的方法传送为委托的一个参数。
2,委托是怎样出现的
在C和C++中,只能提取函数的地址,并传送为一个参数。C是没有类型安全性的。可以把任何函数传送给需要函数指针的方法。这种直接的方法会导致一些问题,例如类型的安全性,在进行面向对象编程时,方法很少是孤立存在的,在调用前,通常需要与实例相关联。而这种方法并没有考虑到这个问题。所以.NET Framework在语法上不允许这种直接飞方法。如果要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊的对象类型,其特殊之处在于,我们以前定义的所有对象都包含数据,而委托包含的只是方法的地址。
3.委托的定义
委托使用和使用一个类一样,分两个阶段。首先定义要使用的委托,定义它就是告诉编译器这种类型的委托代表了哪种类型的方法,然后创建该委托的一个或多个实例。编译器在后台将创建表示该委托的一个类。
定义委托的语法如下:
delegate void IntMethodInvoker(int x);
在这个示例中,定义了一个委托IntMethodInvoker,并指定该委托的每个实例都包含一个方法的细节,该方法带有一个int参数,并返回void。理解委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所代表的方法签名和返回类型等全部细节。理解委托的一种好方式是把委托当做给方法签名和返回类型指定名称。
其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。完成定以后,就可以创建它的实例,以存储特定方法的细节。
4.实例化委托
在C#中,委托在语法上总是带有一个参数的构造函数,这个参数就是委托引用的方法。这个方法必须匹配最初定义委托时的签名。在任何代码中,都应提供委托实例的名称,后面的括号中应包含用该委托中的方法时使用的参数。
给定委托的实例可以表示任何类型的任何对象上的实例方法或者静态方法——只要方法的签名匹配于委托的签名即可。
一旦定义了委托类,就可以实例化它的实例,就像处理一般的类那样——所以把一些委托的实例放在数组中是可以的。
private delegate string GetAString() static void Main() { int x=40; GetAString firstStringMethod=new GetAString(x.ToString); Console.WriteLine(“String is {0}”+firstStringMethod()); }
实际上,给委托实例提供括号与调用委托类的Invoke()方法完全相同。委托实例是委托类型的一个变量,所以C#编译器会用 firstStringMethod.Invoke()代替firstStringMethod()。
GetAString firstStringMethod=new GetAString(x.ToString); 和 GetAString firstStringMethod=x.Tostring;
C#编译器创建的代码是一样的。第二种方法叫委托推断。委托推断可以在需要委托实例的任何地方使用,是C#2.0使用委托推断扩展了委托的语法。
不能用:
x.ToString()
方法把它传送给委托变量.调用x.ToString()方法会返回一个不能赋予委托变量的字符串对象。只能把方法的地址赋予委托变量。
5.多播委托
如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。System。MulticastDelegate的其他成员允许把多个方法调用连接在一起,成为一个列表。
使用方法和事件类似,可以识别+ 、+=和-、-=运算。
其中如果前面的方法抛出异常,委托的迭代就会停止,为了避免这个问题,应该手动迭代方法列表,Delegate类定义了方法GetInvocationList(),它返回一个Delegate对象数组:
DemoDelegate d1=One; d1+=Two; Delegate[] delegates=d1.GetInvocationList(); foreach(DemoDeletate d in deletates) { //process }
6.匿名方法
使用匿名方法的两个规则。
7.λ表达式
可以用于委托类型,可以用于委托是类型的任意地方
λ运算符=>的左边列出了匿名方法需要的参数。右边列出了实现代码
8.协变和抗变
返回类型协变和参数类型抗变