委托事件(转自传智播客邹华栋老师)

一、委托

1.概念:用来存放方法指针(地址)的容器。

为什么要有委托?当有的业务代码总体已经实现,但有部分需要调用者来决定,就可以使用委托的方式,让调用者把一段代码以方法的方式传入。

【例子】:

List<Person> list2 = newList<Person>();

list2.Add(newPerson());

list2.Add(newPerson());

list2.Add(newPerson());

//平时,我们每次需要遍历集合的时候都要手写循环代码

foreach (Person per in list2)

{

    Console.WriteLine(per.SayHi());

}

//使用集合的 ForEach方法,它会帮我们遍历 list2里的元素,但是它不知道每次遍历要对元素做什么事情,需要程序员传入代码(执行代码只能放在方法里,所以这里需要传入一个方法)

list2.ForEach(TakeSayHi);

//准备给ForEach的方法

publicvoidTakeSayHi(Person p)

{

      Console.WriteLine(p.SayHi());

}

【问题】:方法是如何传递的呢?

通过委托类!

2.语法:

2.1简单实用

2.1.1如何定义委托

publicdelegatevoidDGSayHi(Person p);

2.1.2如何创建委托对象

//定义方法(其签名必须与要添加到的委托的签名一致)

publicvoid TakeSayHi(Person p)

{

    Console.WriteLine(p.SayHi());

}

 

//创建委托对象(构造函数中传入方法)

DGSayHi dgSayhi = newDGSayHi(TakeSayHi);

//2.1.3如何调用委托

//1.创建委托对象,传入与委托具有相同签名的方法

DGSayHi dgSayhi = newDGSayHi(TakeSayHi);

//2.调用委托里的方法,并为委托里的方法传入参数

dgSayhi.Invoke(newPerson());

 

2.2将方法当参数(本质是把委托当参数,委托里存放要传递的方法)

//定义需要传递委托参数的方法:

publicvoid TestDGSayHI(DGSayHi dgSayHI)

{

    Person p = newPerson();

    dgSayHI.Invoke(p);//通过委托调用随委托传进来的方法

}

 

//测试:

DGSayHi dg = newDGSayHi(TakeSayHi);

//把方法存在委托中,然后传递给调用方法

TestDGSayHI(dg);

 

2.3将方法当返回值(本质是把委托当返回值,委托里存放要返回的方法)

publicDGSayHi CreateDele(string type) {

    switch (type)

    {

        default:

            returnnewDGSayHi(TakeSayHi);

    }

}

调用:

Person p = newPerson();

//返回一个包含了方法的委托对象

DGSayHi dg = CreateDele("p");

//通过委托调用委托里的方法

dg.Invoke(p);

 

2.4向委托中存放多个方法(多播委托)

DGSayHi dgSay = newDGSayHi(TakeSayHi);

//向委托中追加方法(也存在委托中)

dgSay += newDGSayHi(TakeSayHiInJp);

dgSay += newDGSayHi(TakeSayHiInKr);

//调用的时候按照方法添加的顺序依次执行方法并为每个方法都传入相同参数

dgSay.Invoke(newPerson());

 

2.5移除委托中的方法

DGSayHi dgSay = newDGSayHi(TakeSayHi);

//向委托中追加方法(也存在委托中)

dgSay += newDGSayHi(TakeSayHiInJp);

dgSay += newDGSayHi(TakeSayHiInKr);

//移除委托中的一个方法

dgSay -= newDGSayHi(TakeSayHiInJp);

//调用委托中剩下的两个方法,并传入相同参数

dgSay.Invoke(newPerson());

 

3.语法糖

为了简化语法,.Net编译器会认识一些简单的语法,并在编译的时候转成正常语法代码。因为是在编译的时候替换,所以不会影响运行的效率。

//3.1创建委托执行委托里的方法的  语法糖

DGSayHi dgSayHi2 = TakeSayHi;//new DGSayHi(TakeSayHi);

dgSayHi2(newPerson());//dgSayHi2.Invoke(new Person())

 

//3.2直接把方法作为参数传入

TestDGSayHI(TakeSayHi);// TestDGSayHI(new DGSayHi(this.TakeSayHi));

 

//3.3+= / -=

DGSayHi dgSay2 = TakeSayHi;

dgSay2 += TakeSayHiInJp;

dgSay2 += TakeSayHiInKr;

dgSay2 -= TakeSayHiInJp;

dgSay2(newPerson());

编译后:

DGSayHi dgSay2 = new DGSayHi(this.TakeSayHi);

dgSay2 = (DGSayHi) Delegate.Combine(dgSay2, new DGSayHi(this.TakeSayHiInJp));

dgSay2 = (DGSayHi) Delegate.Combine(dgSay2, new DGSayHi(this.TakeSayHiInKr));

dgSay = (DGSayHi) Delegate.Remove(dgSay, new DGSayHi(this.TakeSayHiInJp));

dgSay2.Invoke(new Person());

 

注意:方法中不能定义类

privatevoid btnDelSelf_Click(object sender, EventArgs e)

{

//class A{}

//delegate void A();//委托就是在一个类,所以也不能在方法中定义委托

}

4.委托原理

4.1定义委托:

publicdelegatevoidDGSayHi(Person p);

 

编译后:会生成一个继承于MulticastDelegate的类!

.class public auto ansi sealedDGSayHi

    extends [mscorlib]System.MulticastDelegate

{

.method public hidebysig newslot virtual instance void Invoke(class 委托事件.Person p) runtime managed

......

}

 

编译后我们看到了一个继承关系:自定义委托类 -> MulticastDelegate ->Delegate

 

4.2委托类 Delegate

DGSayHi dg = newDGSayHi(TestTar);//此处先看成 new 了一个 Delegate

dg(newPerson());

创建委托对象的时候,将方法的地址存入了委托对象里的 MethodPtr变量中

当前所在的窗体对象被存入了委托对象的 _target变量

4.2多播委托 MulticastDelegate

 

 

 

 

 

 

 

5.匿名方法

针对于某些只调用一次的方法,使用匿名方法。

List<Person> list2 = newList<Person>();

list2.Add(newPerson());

list2.Add(newPerson());

list2.Add(newPerson());

//匿名方法

list2.ForEach(delegate(Person p)

{

    Console.WriteLine(p.SayHi());

});

 

 

二、事件 Event

为什么要有事件?

如果所有地方都是用委托,那么有可能发生这种情况:一个委托对象,已经注册了若干方法,但某个程序员不知道,直接将委托设置为 null,清空了所有的方法。

而事件可以为我们限制在外部访问某个类里的委托对象的方式,只能在外部通过 +=/-=操作委托对象。

 

1.语法

//1.先定义委托

publicdelegatevoidDGTripleClick();

//2.定义事件(在某个类中需要使用委托时,加个event关键字)

publiceventDGTripleClick TripleClickEvent;

//3.使用事件

TripleClickEvent += Mehtod1;

TripleClickEvent -= Mehtod1;

TripleClickEvent=null;//报错,事件委托在外部只能在 +=/-=左边

TripleClickEvent();//报错,事件委托在外部不能直接调用执行

2.原理

C# 里的事件 其实是一套类似于 属性的 语法机制

用来 限制 在某个类的外面 访问 类里面的 委托的 方式。

事件会在编译后 自动的生成一个私有的委托变量,同时生成 addon 和 removeon 两个公有的两个方法用来 +=/-= 操作 这个私有委托变量。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值