委托
我们习惯把数据或者对象作为参数传递给方法,比如:
int i = int.Parse("99");
如果我们把方法作为参数传递给方法,这就需要用到委托了。我们从字面上理解委托,就像是A委托B去办一件事情一样,其实在C#中也有这一层的含义。
首先我们先看C#中的语法:
public delegate void DoSomethingEventHandler();
delegate是关键字,EventHandler算是一个声明委托类型的一个命名标准。委托的定义就这么简单。
让我们先来看一段代码:
class Student {
public static void MakeTea() {
Console.WriteLine("Got it!");
}
}
class Teacher
{
//声明一个委托
public delegate void DoSomething();
static void Main(string[] args)
{
//给委托传递具体方法
DoSomething myDelegate = new DoSomething(Student.MakeTea);
//委托被赋予了具体的方法
myDelegate();
}
}
我们来看一下我们定义的委托和委托被赋予的方法:
public delegate void DoSomething();
public static void MakeTea() {
/..../
}
或许这样比较并看不出什么,毕竟我们对委托还没有具体的认识,所以我们来看一下委托的一些规定:
C#中委托的参数和返回类型,都要和你要具体委托的方法要一致。我们再来看一下委托时如何运作的:
DoSomething myDelegate = new DoSomething(Student.MakeTea);
myDelegate();
或许有C++基础的已经看出来了,委托和C++中的函数指针类似。确实委托就可以看做一个函数指针。所以才会有委托的参数和返回值必须和具体委托的方法一致的规定。
多播委托
多播委托其实也很简单。我们先看代码:
class Student {
public static void MakeTea() {
Console.WriteLine("Got it!");
}
public static void BuyPen() {
Console.WriteLine("On my way");
}
}
class Teacher
{
//声明一个委托
public delegate void DoSomething();
static void Main(string[] args)
{
//给委托传递具体方法
DoSomething myDelegate = new DoSomething(Student.MakeTea);
myDelegate += Student.BuyPen;
//委托被赋予了具体的方法
myDelegate();
}
}
我们看到Student中添加了一个BuyPen的功能,我们只是在程序中加了myDelegate += Student.BuyPen;
这就相当于要做两件事,显示倒茶,然后去买笔。其实是委托中重载了“+=”这个运算符,我们才可以以这种方法创建委托链。相对的我们可以用“-=”来销毁这个委托链。
事件
点击事件,加载事件充斥在我们的日常编程中,我们对事件都有一个模糊的认识。下面我们来看一下比较官方的概念:事件是类在发生其关注的事情时用来提供通知的一种方式。
我们先看一段代码:
/// <summary>
/// 含有姓名和年龄属性,并重写了ToString方法
/// </summary>
class PersonEventArgs:EventArgs
{
string name;
int age;
public PersonEventArgs() { }
public PersonEventArgs(PersonEventArgs person) {
this.name = person.name;
this.age = person.age;
}
public PersonEventArgs(string name,int age) {
this.name = name;
this.age = age;
}
public override string ToString()
{
return string.Format("name is {0},age is {1}!",name,age);
}
}
//声明一个添加人员的委任
delegate void AddPersonEventHandle(object sender,PersonEventArgs args);
class AddPersonListener
{
//在委托的机制下我们建立一个添加事件
public event AddPersonEventHandle addPerson;
ArrayList personList = new ArrayList();
/// <summary>
/// 当我们向列表中添加一个对象时就触发该事件
/// </summary>
/// <param name="person"></param>
public void AddPerson(PersonEventArgs person) {
personList.Add(person);
//多路广播
addPerson += new AddPersonEventHandle(AddPersonListener_addpersonEvent);
//检测到监听的事件
OnAdd(person);
}
//具体委托的方法
void AddPersonListener_addpersonEvent(object sender, PersonEventArgs args)
{
Console.WriteLine(args.ToString());
}
//声明一个可以被重写的OnAdd的保护函数
public virtual void OnAdd(PersonEventArgs args) {
if (addPerson != null) {
addPerson(this, args);
}
}
}
class Program
{
static void Main(string[] args)
{
AddPersonListener listener = new AddPersonListener();
PersonEventArgs person = new PersonEventArgs("Joea");
listener.AddPerson(person);
}
}
上面的代码是实现一个我们向personList中添加一个对象时就把对象中的name打印出来。在其中我们定义个一个事件addPerson,关键字是event。在我们使用事件的时候,必须要声明对应的委托,而触发事件,其实就是在使用委托链。
最后我们有必要搞懂.Net Framework的编码规范:
- 委托类型的名称都应该以 EventHandler结束。
- 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
- 事件的命名为 委托去掉 EventHandler之后剩余的部分。
- 继承自EventArgs的类型应该以EventArgs结尾。