C#中委托和时间是个坎,了解的人绝的就是那么回事,没吃透的人总是觉的碰见一次迷糊一次,我就是接与两者之间,也算站在坎上,但是稍稍理解了一些,希望通过这篇文章,让迷茫的同学,稍微的理解一下。
在这里推荐Jimmy Zhang(张子阳)的一篇博文C# 中的委托和事件,他讲解的非常好,比书上那些概念罗列要出色的多。推荐大家看一下,到时候应该会理解很深,我写这个博文的原因是主要是为了让自己理解一下,日后可以翻看一下。
OK,首先还是说一下委托的概念,《C#高级编程》当头一句,委托是寻址方法的.Net版本。为了好理解就是可以认为是方法指针(当然往上有些人不推荐,说高级程序员都不是这么理解的,可是咱现在没办法,只能先这么认为),就是可以在里面传方法,就想传递引用参数一样。
其实委托最难懂的地方应该就是以前没接收过类似的概念,新概念的生成需要一段时间,就比如如果学过HTML,再学XML,就会对标签不那么陌生。委托一出来,感觉就怪怪的,将方法作为参数,以前很少这么用啊,(C++有,但是我菜鸟。大侠无视)。
基础的小例子在上面的博文里讲得很详细,可能有很多人开始和我一样,觉得书上讲的这些话,
定义委托的语法如下:
delegate IntMethodInvoker(int x);
在这个示例中,定义了一个委托,并指定该委托的每个实例都可以包含一个
方法的引用,该方法带有一个血参数,并返回voⅡ。理解委托的一个要点是它们的类型安全性非
常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。
就会觉的,天啊,这是什么啊。其实就是个名字而已,就好像有人告诉你有一只非洲猫鼬叫“Smelly Cat”,不管他,反正就是个名字,但是里面的参数一定要和你调用的方法的参数,或者说是函数签名一致哦。否则它不知道怎么处理。然后委托可以多播委托,就是一个委托干很多件事情,添加和删除是需要用“+=”和“-=”来处理,其实这里用到的不是很多,往后你们见到的都是事件和委托在一起的时候。那事件又是什么东西,事件就是触发之后处理,这个应该都接触过,但是事件的类型是什么,OK这里就是要用的到委托了。说的都混乱了。
看下面一个例子,我编写了一个老师点名的程序,通过在老师类里面的委托注册,可以知道学生的数目,然后点名的时候,注册的学生会答到。
首先是学生类,里面有一个方法来答到,委托是方法的指针,肯定要有一个方法作为委托的参数,就是它
public void Answer(string name)
很简单,就是看看叫道的是不是自己的名字,传入的name就是老师点的名字
//如果名字相同,就喊“到”
public void Answer(string name)
{
if (name.Equals(this.name))
{
Console.WriteLine("{0} say:I'm here!", name);
}
}
学生类完整代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateTest
{
class Student
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Student(string name)
{
this.name = name;
}
//如果名字相同,就喊“到”
public void Answer(string name)
{
if (name.Equals(this.name))
{
Console.WriteLine("{0} say:I'm here!", name);
}
}
}
}
接下来石老师了,老师很重要,首先需要定义一个委托,用来传递方法,
public delegate void CallNameHander(string name);//declare delegate
因为它是方法的指针嘛,不能忘了,然后再顶一个事件,
public event CallNameHander CallNameEvent;//declare event
这个就是事件,你可能会觉得event 和CallNameEvent中间加的东西很眼熟,对了,就是刚刚的委托,为什么是它,我也不知道,但是就是这么规定的,你可以认为这是在告诉编译器事件是处理谁的委托的。
然后就是亲爱的点名函数了,当有人点名的时候,就会触发事件,CallEvent就不为空,然后就是事件处理了,调用了传进去的方法。
老师类完整代码using System;
namespace DelegateTest
{
public delegate void CallNameHander(string name);//declare delegate
class Teacher
{
public event CallNameHander CallNameEvent;//declare event
public void CallName(string name)
{
if (CallNameEvent != null)
{
CallNameEvent(name);
}
}
}
}
最后来进行点名了,首先需要一个老师和几个学生,OK
Teacher teacher = new Teacher();
Student tom = new Student("tom");
Student jack = new Student("jack");
Student marry = new Student("marry");
他们来了。然后老师说来点名了,这时候有谁来了,大家就会答到,
teacher.CallNameEvent += new CallNameHander(tom.Answer);
teacher.CallNameEvent += new CallNameHander(jack.Answer);
teacher.CallNameEvent += new CallNameHander(marry.Answer);
这几句的意思就是他们来到了课堂,而且已经注册了answet方法,就是知道自己要干什么----答到。
这时候恐怖的一幕发生了,老师拿起了点名册,然后恐吓超过多少次就取消成绩云云(大学生的痛),然后开始,
teacher.CallName("tom");
这是调用了CallName,如果没记错,里面可是有个事件的,这里事件就是此奥用了,你要是问为什么,我也说不清,就是规定。然后就是以此达到
下一节课,杰克回家了饿,他就悲剧了。
点名测试
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateTest
{
class Test
{
static void Main(string[] args)
{
Teacher teacher = new Teacher();
Student tom = new Student("tom");
Student jack = new Student("jack");
Student marry = new Student("marry");
Console.WriteLine("---------------------------------");
Console.WriteLine("Math Teacher say: Now Call Name!");
teacher.CallNameEvent += new CallNameHander(tom.Answer);
teacher.CallNameEvent += new CallNameHander(jack.Answer);
teacher.CallNameEvent += new CallNameHander(marry.Answer);
Console.WriteLine("Math Teacher say: tom!");
teacher.CallName("tom");
Console.WriteLine("Math Teacher say: jack!");
teacher.CallName("jack");
Console.WriteLine("Math Teacher say: marry!");
teacher.CallName("marry");
Console.WriteLine("---------------------------------");
Console.WriteLine("then jack go home");
Console.WriteLine("---------------------------------");
teacher.CallNameEvent -= new CallNameHander(jack.Answer);
Console.WriteLine("English Teacher say: Now Call Name!");
Console.WriteLine("Math Teacher say: tom!");
teacher.CallName("tom");
Console.WriteLine("Math Teacher say: jack!");
teacher.CallName("jack");
Console.WriteLine("Math Teacher say: marry!");
teacher.CallName("marry");
Console.ReadKey();
}
}
}
运行结果