C#委托及事件委托的初步理解
委托的声明
public delegate void MyDelegate(string str);
委托是一种特殊的类型(class),用途是来实现对一种方法的封装。在某种事件发生时,自动调用该方法。好处显然易见,它使用户可以自定义自己的方法实现,通过封装,CLR会在相应事件激发时调用你定义的方法,实现你的功能。
注
1.委托的定义和方法的定义类似,只是在前面加了一个delegate,但委托不是方法,它是一种类型。是一种特殊的类型,看成是一种新的对象类型比较好理解。用于对与该委托有相
同签名的方法调用。
2.委托相当于C++中的函数指针,但它是类型安全的。
3.委托是从System.Delegate派生,但不能象定义常规类型一样直接从System.Delegate派生,对委托的声明只能通过上面的声明格式进行定义。关键字delegate通知编译器这是一
个委托类型,从而在编译的时候对该类进行封装,对这一过程C#定义了专门的语法来处理这一过程。
4.不能从一个委托类型进行派生,因为它也是默认sealed的
5.委托即可以对静态方法进行调用也可以对实例方法进行调用。
6.每个委托类型包含一个自己的调用列表,当组合一个委托或从一个委托中删除一个委托时都将产生个新的调用列表。
7.两个不同类型的委托即使它们有相同的签名和返回值,但还是两个不同类型的委托。但其实在使用中可看作是相同的。
委托的比较
C#中对委托定义了两个操作符 == 和 !=
在以下情况下两个委托是相等的:
1.当两个委托都同时为null的时候
2.当两个委托都不为null时,下列情况下是相等的。
a.当两个委托的各自的调用列表只含有一个入口点的时候
在下列情况下是相等的
(1) 调用同一对象的同一静态方法
(2) 调用同一对象的同一实例方法
b.当两个委托具有多个入口点时
在下列情况下是相等的
(1)只有当它们调用列表中的调用的方法按顺序都一一对应相同的对象及对象的同一方法的时候
如上所述的两个不同类型的委托但是它们具有相同的签名和返回值时,只要满足上述条件的,即使它们类型不同,但比较的结果也是相同的。
委托的异常处理
当调用该委托的方法中发生了异常时,首先在调用该委托的方法中搜寻catch语句块。如果没有,则去该委托调用的方法中去寻找有没有catch语句块,这和调用方法发生异常的处
理是一样的。
当调用一个为null的委托即委托中列表中不存在调用方法时,将发生NullRefrenceException
委托的注意点:
当一个委托有多个入口点的时候,调用委托将依该委托的调用列表中的方法的顺序依次调用.这些方法共享一个参数集合,所以当委托有返回值的时候调用完这个委托后的返回值是最
后一个方法的返回值或是有out参数.如果该委托的参数为ref(引用类型),那么在招待第一个方法的时候如果对这个参数的值有所改变,那么这个改变将会影响到后面的方法调用.
委托的一个例子:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace ConsoleApplication1
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 // 创建一个委托实例,封装C类的静态方法M1
12 MyDelegate d1 = new MyDelegate(C.M1);
13 d1("D1"); // M1
14
15 // 创建一个委托实例,封装C类的静态方法M2
16 MyDelegate d2 = new MyDelegate(C.M2);
17 d2("D2"); // M2
18
19 // 创建一个委托实例,封装C类的实例方法M3
20 MyDelegate d3 = new MyDelegate(new C().M3);
21 d3("D3"); // M3
22
23 // 从一个委托d3创建一个委托实例
24 MyDelegate d4 = new MyDelegate(d3);
25 d4("D4"); // M3
26
27 // 组合两个委托
28 MyDelegate d5 = d1 + d2;
29 d5 += d3;
30 d5("D5"); // M1,M2,M3
31
32 // 从组合委托中删除d3
33 MyDelegate d6 = d5 - d3;
34 d6("D6"); // M1,M2
35 d6 -= d3; // 虽然d6调用列表中已经没有d3了,但这样只是不可能的移除没有错误发生
36 d6("D6"); // M1,M2
37 d6 -= d6;
38 //d6("D6"); 此时d6的调用列表为空,d6为null,所以引发System.NullReferenceException
39
40 MyDelegate d7 = new MyDelegate(C1.P1);
41 d7("D7"); // C1.P1
42
43 MyDelegate d8 = new MyDelegate(new C2().P1);
44 d8("D8"); // C2.P1
45
46 }
47 }
48
49 // 声明一个委托MyDelegate
50 public delegate void MyDelegate(string str);
51
52 public class C
53 {
54 public static void M1(string str)
55 {
56 Console.WriteLine("From:C.M1: ", str);
57 }
58
59 public static void M2(string str)
60 {
61 Console.WriteLine("From:C.M2: ", str);
62 }
63
64 public void M3(string str)
65 {
66 Console.WriteLine("From:C.M3: ", str);
67 }
68 }
69
70 public class C1
71 {
72 public static void P1(string str)
73 {
74 Console.WriteLine("From:C1.P1: ", str);
75 }
76 }
77
78 public class C2
79 {
80 public void P1(string str)
81 {
82 Console.WriteLine("From:C2.P1: ", str);
83 }
84 }
85 }
86
以上来自CSDN博客,转载请标明出处:http://blog.csdn.net/gb1983/archive/2007/03/20/1534922.aspx
这是另一个例子:仔细揣摩
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace 委托_练习_4
7 {
8 class Program
9 {
10 public delegate int Del(int i,int j);
11 static void Main(string[] args)
12 {
13 b dd=new b();
14 a cc = new a();
15 Del song = dd.Max;
16 Console.WriteLine("__________________ {0}",song(5,1));
17 Console.WriteLine("__________________ {0}",dd.testA());
18 Console.ReadKey(true);
19 }
20 class a
21 {
22 public int A, B;
23 public int GetResult(Del m)//接收参数(此参数是下面传过来的一个委托)
24 {
25 return m(A,B);
26 }
27 }
28 public class b
29 {
30 internal int testA()
31 {
32 a abc = new a();
33 abc.A = 10;
34 abc.B = 5;
35 //实例化了一个委托(传递委托实例)
36 int h = abc.GetResult(new Del(Max));
37 return h;
38 }
39 public int Max(int i1, int i2)
40 {
41 return i1 > i2 ? i1 : i2;
42 }
43 }
44 }
45 }
调用委托
1 调用委托 使用和调用方法相同的方法。 例如:
2 myDelegate del();
3 ...
4 del();
声明事件
选定关键字event,再写类型的名称(类型必须是一个委托类型),再写事件的名称,例如:
1 delegate void myDelegate();
2 class MyClass
3 {
4 public event myDelegate MyEvent;
5 }
订阅事件(成为事件的订阅者)
用new操作符创建一个委托实例(该委托具有与事件相同的类型)然后使用+=操作符,将委托实例同事件关联起来。例如:
1 class MyEventHandlingClass
2 {
3 ...
4
5 public void Start()
6 {
7 myClass.MyEvent+=new myDelegate(this.eventHandlingMethod);
8 }
9
10 private void eventHandlingMethod()
11 {
12 ...
13 }
14 private MyClass myClass=new MyClass();
15 }
还可以直接指定订阅方法,让编译器自动生成新的委托:
1 public void Start()
2 {
3 myClass.MyEvent += this.eventHandlingMethod;
4 }
取消事件订阅(不再成为一个事件的订阅者)
创建一个委托实例(该委托具有与事件相同的类型),然后使用+=操作符使委托实例从事件中脱离。例如:
1 class MyEventHandlingClass
2 {
3 ...
4 public void Stop()
5 {
6 myClass.MyEvent-=new myDelegate(this.eventHandlingMethod);
7 }
8
9 private void eventHandlingMethod()
10 {
11 ...
12 }
13 private MyClass myClass=new MyClass();
14
15 }
16 或者:
17 private void Stop()
18 {
19 myClass.myEvent-=this.eventHandlingMethod;
20 }
引发一个事件
像调用方法那样“调用”事件(在事件名称后添加一对圆括号)。如果定义事件的委托要求参数,那么还是提供对应的。引发事件之前,不要忘记检查事件是否为null。例如:
1 class MyClass
2 {
3 public event myDelegate MyDelegate;
4 ...
5 private void RaiseEvent()
6 {
7 if(this.MyEvent!=null)
8 {
9 this.MyEvent();
10 }
11 }
12 ...
13 }
以下来自CSDN博客,转载请标明出处:http://blog.csdn.net/gb1983/archive/2007/03/20/1534922.aspx
事件的声明
1.声明一个委托
public delegate void EventHandler(object sender, System.EventArgs e);
2.声明一个事件
public event EventHandler Changed;
3.引发一个事件
1 public OnChanged(EnventArgs e)
2 {
3 if ( Changed != null)
4 {
5 Changed(this,e);
6 }
7 }
4.定义事件处理程序
public MyText_OnChanged(Object sender,EventArgs e)
5.订阅事件(将事件处理程序添加到事件的调用列表中)
myText.Changed += EventHandler(MyText_OnChanged);
下面的一个小例子说明了怎样定义一个完整的事件机制:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace ConsoleApplication1
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 MyText myText = new MyText();
12
13 // 将事件处理程序添加到事件的调用列表中(即事件布线)
14 myText.Changed += new MyText.ChangedEventHandler(myText_Changed);
15
16 string str = "";
17 while (str != "quit")
18 {
19 Console.WriteLine("please enter a string:");
20 str = Console.ReadLine();
21 myText.Text = str;
22 }
23 }
24
25 // 对Change事件处理的程序
26 private static void myText_Changed(object sender, EventArgs e)
27 {
28 Console.WriteLine("text has been changed :n" ,((MyText)sender).Text);
29 }
30 }
31
32 public class MyText
33 {
34 private string _text = "";
35
36 // 定义事件的委托
37 public delegate void ChangedEventHandler(object sender, EventArgs e);
38
39 // 定义一个事件
40 public event ChangedEventHandler Changed;
41
42 // 用以触发Change事件
43 protected virtual void OnChanged(EventArgs e)
44 {
45 if (this.Changed != null)
46 this.Changed(this, e);
47 }
48
49 // Text属性
50 public string Text
51 {
52 get { return this._text; }
53 set
54 {
55 this._text = value;
56 // 文本改变时触发Change事件
57 this.OnChanged(new EventArgs());
58 }
59 }
60 }
61 }