您的位置:首页 > 其它

.NET 委托和事件

2016-02-14 14:46 218 查看

       什么叫委托

       委托就是只想一个函数的指针,使用委托可以让方法的引用封装在委托对象内,例如我是老板,需要以后我渴了的时候让小蜜给我打杯水,饿了就让他给我打水,门上安装个门铃,一按就让她给我打水和送吃的。这样我就可以将委托,将引用方法(打水)封装到委托对象(小蜜),以后我一按门铃,那么就是告诉我小我要喝水了,要吃东西了,小蜜就给我打水,至于门铃到底代表了什么,不管,我只是我说我又饿又渴,哈哈哈,我是不是太懒了。

      委托实现

     代码实现

         其实学习.net的大家应该都知道有这么一个东西,那么我们就先看一下,这个家伙怎么用。例如一个简短的例子:

<span style="font-size:14px;">class Program
{
//定义一个委托类型的saySomething,参数是name,返回值是void
public delegate void saySomething(string name);

static void Main(string[] args)
{
//调用委托方法
saySomething ss = new saySomething(saySome.sayHelloToChinese);
ss += new saySomething(saySome.sayHelloToEnglish);
ss("孟海滨");
ss("平晓微");
ss.Invoke("孟海滨");
Console.ReadLine();
}
}

public class saySome
{
/// <summary>
/// 一个静态方法,简单的打印一句话
/// </summary>
/// <param name="name">一个姓名的参数</param>
public static void sayHelloToChinese(string name)
{
Console.WriteLine(name + ":你好");
}

/// <summary>
/// 一个静态方法,简单的打印一句话
/// </summary>
/// <param name="name">一个姓名的参数</param>
public static void sayHelloToEnglish(string name)
{
Console.WriteLine(name + ":hello");
}
}</span>
         看一下运行结果

      


          分析代码

       1.public delegate void saySomething(string name);   这里申明了一个Delegate的类型,名称为saySomething,返回值是void,参数是string

       2.为什么在最开始我说是一个函数的指针呢,大家看这行代码: ss += new saySomething(saySome.sayHelloToEnglish);他代表的就是指向saySome.sayHelloToEnglish这个函数。当然他和C++的函数指针还是有区别的,首先他可以搭载多个函数,而C++只能搭载一个,委托是安全的,面向对象的。

      3.Delegate在搭载多个方法时,可以通过+=增加搭载的函数,也可以通过-=来去掉Delegate中的某个函数。

      什么时候用

         加入有这么一个需求,汽车开车,当开到一定的距离的时候,报警器报警,就是是一次开到太多了,现在是汽车是一个实体,而报警器也是一个实体,如果用委托,他们可以这样实现。大家先看代码:

      汽车实体

<span style="font-size:14px;">public class Car
{
//定义委托类型,返回值是void,参数是int
public delegate void Notify(int value);
//定义一个事件
public event Notify notifiers;

//定义一个汽油的变量
private int petorl;
//汽油变量的set,get方法,在设置汽油数值的时候,判断汽油量是否充足
public int Petorl
{
get { return petorl; }
set {
petorl = value;
//如果汽油量少于10
if (petorl < 10)
{
//如果委托的对象不为空
if (notifiers != null)
{
//执行委托的放方法,委托的是什么?在这里不体现。
notifiers.Invoke(Petorl);
}
}
}
}

//构造函数,参数为汽油量(单位 :/L)
public Car(int pertorl) {
Petorl = pertorl;
}

//汽车启动的方法
public void run(int speed) {
//行走公里变量,单位(km/h)
int distance = 0;

//根据汽油量进行循环
while (Petorl > 0)
{
//加上500ms跑speed公里
Thread.Sleep(500);
//汽油逐渐减少
Petorl--;
//行走公里数增加
distance += speed;
Console.WriteLine("汽车当前跑的公里数是" + distance.ToString());
}
}
}</span>
       报警器
<span style="font-size:14px;">public class Alerter
{
//构造函数,将“显示汽油量不足的信息”的引用添加到汽车的委托中
public Alerter(Car car)
{
//为car.notifiers 添加NotEnoughPetorl的引用
car.notifiers += new Car.Notify(NotEnoughPetorl);
}

//显示汽油量不足的信息
public void NotEnoughPetorl(int value)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("汽油量不足了" + value.ToString());
Console.ResetColor();

}
}</span>


        客户端
<span style="font-size:14px;"> class Program
{
static void Main(string[] args)
{
//新建一个汽车,初始化的汽油量是15L
Car car = new Car(15);
//实例化报警器,将新建的气喘告诉他,让他添加一个油量不足的引用
new Alerter(car);
//奔跑吧汽车
car.run(120);
}
}</span>

        看到上边的代码,有的朋友就会说了,我不用再汽车(Car)类里边用委托,直接实例化Alerter也可以呀,直接实例化,如果汽油量少于10,我就实例化一个报警器,然后去执行油量不足的提醒,也可以呀!

       是的,确实可以,但是看看如果我用了委托,我再汽车中有关于警报器的说法吗,是不是解耦合了,假如改天我的汽车改成烧气 的了,怎么办,我需要新加一个方法(提示天然气不足的),这个本来没什么,有了新的需求,增加代码本来就是应该的,但是我如果实例化报警器的话,那么我就需要修改汽车的类了,如果是委托呢,我执行要在报警器的类中做一定的扩充就可以,以前的代码完全不用改。这样看的话,是不是感觉委托更加牛了呢。

      Delegate和event

      大家可能看到上边有那么两句代码

//定义委托类型,返回值是void,参数是int
public delegate void Notify(int value);
//定义一个事件
public event Notify notifiers;
      这个事件是什么鬼,为什么我在第一个代码示例中就可以实现委托的功能,却要假一个事件,event与纯粹的delegate变量的最大区别就是增加了封装性。让delegate的触发权完全由对象控制,而delegate所委托的实际函数则由订阅者决定。event就是要执行一种“什么时候发生我说了算,发生的时候做什么事你说了算“的效果。而纯粹的delegate变量则在可访问的范围内同时给与指定委托函数与触发的权限。

      invoke和BeginInvoke的区别

     在第一个例子我用到了ss("孟海滨"),ss.invoke("孟海滨"),为什么要用invoke,他是个什么鬼invoke和BeginInvoke有详细的解释,大家可以看一下,这里我就不解释了。

     委托小结

       当我们在方法中需要函数指针等类似的东西的时候,当我们需要使用观察者模式的时候,当我们需要回掉函数的时候,可以考虑一下我们的委托,让我们降低类之间的耦合
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: