系列文章目录
前言
拜读了博客园大佬一篇相关文章,我感觉对委托和事件的理解比昨天更深了些,特此记录。
大佬文章地址
一、委托的理解
昨天只是对委托,事件的使用做了简单介绍,但是我所需要的是理解,都说对委托和事件的理解是一道分水岭,要重点理解。
先上几条我理解的结论:
- 在我们需要分多种情况进行不同的处理时,委托可以避免使用大量的
if..else(switch)
- 委托是一种类型,或者说类
- 对委托的定义即是对所需方法的约束,体现在返回值和参数列表上
- 委托可以依次调用多个绑定的方法
1.为什么需要委托?
我们现在假设这样一个程序需求:A学院的六级成绩不太理想,设置了一个激励措施
及格者 奖励分数双倍的人民币
public static void GetBonus(int score)
{
if(score >= 425)
{
Console.WriteLine("你获得了奖金:{0}",score*2);
}
}
先不要管它的实际意义,现在只要输入大于等于425的成绩就可以获得双倍,结果下次考试成绩明显有所好转,学校决定加大力度,这次添加了更新了标准:
及格且在450分以下的 按分数2倍
450分及以上的 2.5倍
这样该怎么设计呢,你肯定会觉得我再加一个判断不就得了,那要是学校闲的,一分一个标准呢,你难道真的要那样直接在原代码中修改吗?(这里只是说明会有很多需要判断的情况)
public static void GetBonus(int score)
{
if (score >= 425 && score < 450)
{
PassOne(score);
}
if (score >= 450)
{
PassTwo(score);
}
}
public static void PassOne(int score)
{
Console.WriteLine("你获得了奖金:{0}",score*2);
}
public static void PassTwo(int score)
{
Console.WriteLine("你获得了奖金:{0}",score*2.5);
}
这样拓展性是非常差的,现在用委托来处理这一需求
public delegate void BonusDelegate(int score);
class DelegateTest
{
public static void GetBonus(int score)
{
if (score >= 425 && score < 450)
{
PassOne(score);
}
if (score >= 450)
{
PassTwo(score);
}
}
public static void PassOne(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2);
}
public static void PassTwo(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2.5);
}
static void Main(string[] args)
{
BonusDelegate bonusDelegate;
bonusDelegate = PassOne;
bonusDelegate += PassTwo;
GetBonus(480);
Console.ReadLine();
}
}
你可以尝试一下,当我们再次添加别的奖励机制的时候,只需要重新加一个方法即可,不需要对原有的代码进行修改,这样的程序的拓展性是非常好的,这也避免了大量使用判断的情况,造成代码冗余和破坏拓展性。
委托的特性
在开头的结论中就有所总结
- 委托是一种类型,是类
class
这一点不难理解,就像是string name
,这里的是string
是什么啊,是对参数的类型吧,而委托就是把方法作为参数
public delegate void HelloDelegate(string name);
public void HelloPeople(string name, HelloDelegate hellodelegate)
{
Hello(name);
}
如上面所展示的,和string
类比,HelloDelegate
也是一种引用类型,也就是类,不过只是它的参数是方法而已,以方法为参数。
- 对委托的定义即是对所需方法的约束,体现在返回值和参数列表上
这句话的我是这么理解的,以方法为参数,我们不能什么方法都可以绑定在一个委托上,需要有一定的限制,而这些限制体现为定义委托时的返回值和参数列表上…
public delegate void BonusDelegate(int score);
public void PassOne(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2);
}
public void PassTwo(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2.5);
}
我们可以观察下,上面的例子,是不是委托比方法只是多了一个delegate
关键字,这就是委托和方法之间的关系,像是一种模板…
- 委托可以依次调用多个绑定的方法
这个的就比较好理解了,上面的例子已经使用过了,当我们使用委托时,当然希望它可以适应多种情景,省时间。
在上面的例子中,我们输入分数时,需要进行很多次判断,每次判断都是一个方法的执行,我们不能一个委托只能执行一个方法吧,那就没有存在的意义了。
二、事件的理解
1.封装性
继续上面的例子,我们进行一些改进,将GetBonus
方法放入类中
代码如下(示例):
public delegate void BonusDelegate(int score);
class DelegateTest
{
class Bonus
{
public void GetBonus(int score)
{
if (score >= 425 && score < 450)
{
PassOne(score);
}
if (score >= 450)
{
PassTwo(score);
}
}
}
public static void PassOne(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2);
}
public static void PassTwo(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2.5);
}
static void Main(string[] args)
{
BonusDelegate bonusDelegate;
bonusDelegate = PassOne;
bonusDelegate += PassTwo;
Bonus.GetBonus(480);
Console.ReadLine();
}
}
运行之后也是正常输出了
在这里,就有一个问题,C#是面向对象的语言,在面向对象的设计中,封装,继承,多态是重要的她特征。
我们现在的代码中的委托,好像谁都可以获取并加入,这并不符合封装的设计思想,现在来委托封装到类中去
class DelegateTest
{
public class Bonus
{
public BonusDelegate bonusDelegate;
public void GetBonus(int score)
{
if (score >= 425 && score < 450)
{
bonusDelegate(score);
}
if (score >= 450)
{
bonusDelegate(score);
}
}
}
public static void PassOne(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2);
}
public static void PassTwo(int score)
{
Console.WriteLine("你获得了奖金:{0}", score * 2.5);
}
static void Main(string[] args)
{
Bonus bonus = new Bonus();
bonus.bonusDelegate = PassOne;
bonus.bonusDelegate += PassTwo;
bonus.GetBonus(480);
Console.ReadLine();
}
}
现在是封装进去了,但是是public
的就意味着,我们可以在客户端对该字段进行任意修改,并不符合封装性的要求。
我们应如何保证封装性呢?
事件就是来做这件事的,它封装了委托类型的变量,使得:
- 在类的内部,不管你声明它是public还是protected,它总是private 的
- 在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同
这是加入事件Event
后的代码
public class Bonus
{
public event BonusDelegate bonusDelegate;
public void GetBonus(int score)
{
if (score >= 425 && score < 450)
{
bonusDelegate(score);
}
if (score >= 450)
{
bonusDelegate(score);
}
}
}
感觉没啥区别,只是多了一个event
关键字,但是这次
看到这里,就可以知道,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已
总结
委托
- 在我们需要分多种情况进行不同的处理时,委托可以避免使用大量的
if..else(switch)
- 委托是一种类型,或者说类
- 对委托的定义即是对所需方法的约束,体现在返回值和参数列表上
- 委托可以依次调用多个绑定的方法
事件
- 声明一个事件不过类似于声明一个进行了封装的委托类型的变量