delegate&event

奇怪的知识又增加了

装箱和拆箱

装箱:栈中的值类型数据复制到堆中,并且建立一个引用指向堆中的值,然后使用这个引用。
拆箱:堆中的值类型数据被复制到栈中,并且直接使用这个值。

以前一直以为装箱和拆箱只是一个值类型和一个引用类型的互相转换,没想到堆栈的层面。栈帧和堆栈的概念之前也只在Java虚拟机中看到过相关的概念。没想到.net的CLR也有一样的概念。实属涨知识了。


delegate

最早接触delegate可以追溯到还在玩windowsform开发的时候,后来的wpf开发也碰到过同样的问题,就是跨窗口调用函数或者跨窗口、线程更新ui。由于安全机制不允许跨窗口或者线程直接调用当前窗口或者线程的函数,于是查了查,就得知了delegate委托。实际上在上学的时候,也有过相关概念的介绍,但是由于没怎么实战过,因此也算是过目就忘。因此特意拿出来集中看一下。

delegate和Delegate
在我们向IDE中输入delegate的时候,也会出现一个Delegate可供选择。

delegate:委托关键字,可以用来定义一个委托类型。比如说:

public delegate void SayHello(string sth);

Delegate:表示委托类型,可以用来继承定义自己的委托类型。目前没碰上过此类用法,因此不再深究。到用的时候再深入研究吧。

委托实际上就相当于把一个与定义好的委托类型形式相等的函数作为参数记录、传入后再使用。使用的时候可以如下形式:

public class EventAndDelegate
{
    public delegate void SayHello(string sth);
    protected SayHello delegateSayHello;
    public EventAndDelegate() { }
    public void AddDelegate(SayHello delegateSayHello)
    {
        this.delegateSayHello += delegateSayHello;
    }
    public void RemoveDelegate(SayHello delegateSayHello)
    {
        this.delegateSayHello -= delegateSayHello;
    }
    public void SayIt(string str)
    {
        if (delegateSayHello != null)
        {
            delegateSayHello(str);
        }
    }
    public static void Say1(string str)
    {
       Console.WriteLine("this is say 1 ... " + str);
    }
    public static void Say2(string str)
    {
        Console.WriteLine("this is say 2 ... " + str);
    }
}

Main函数在调用时:

 static void Main(string[] args)
 {
     EventAndDelegate ead = new EventAndDelegate();
     ead.AddDelegate(EventAndDelegate.Say1);
     ead.AddDelegate(EventAndDelegate.Say2);
     ead.SayIt("skii");
     ead.AddDelegate(EventAndDelegate.Say1);
     ead.RemoveDelegate(EventAndDelegate.Say2);
     ead.RemoveDelegate(EventAndDelegate.Say2);
     ead.SayIt("123");
     Console.ReadKey();
}

从上到下的的含义分别为:
1、定义一个EventAndDelegate实体类为ead。
2、给ead的委托delegateSayHello增加一个委托回调Say1函数。
3、给ead的委托delegateSayHello增加一个委托回调Say2函数。
4、此时ead的委托delegateSayHello就拥有了Say1和Say2两个委托函数,在执行SayIt函数时的输出为:

this is say 1 ... skii
this is say 2 ... skii

5、再给ead的委托delegateSayHello增加一个委托回调Say1函数。
6、给ead的委托delegateSayHello去除一个委托回调Say2函数。
7、再给ead的委托delegateSayHello去除一个委托回调Say2函数,这个步骤主要用来测试delegate委托的健壮性,看看会不会报错,很明显它没有报错。
8、此时的ead委托delegateSayHello应当拥有2个Say1委托函数,在执行SayIt函数时的输出为:

this is say 1 ... 123
this is say 1 ... 123

结论
于是至此为止,我们可以想象delegate的作用,它可以定义一种函数的形式类型,然后把对应的函数当做参数进行处理。


event

在上述delegate了解之后,不难想象,我们可以实现一个简单的事件订阅机制,利用delegate将同一组触发事件绑定在同一个delegate委托上,例如上述的DelegateAndEvent中的delegateSayHello属性(property)。可以看到上述代码示例中,我将delegateSayHello属性定义成了protected,并且使用函数的形式对该属性进行赋值,这个主要还是Java中的封装思想,还算比较规范。那么如果把这个delegateSayHello属性定义成public的话,是不是就意味着这个委托可以在外部被随意更改,这样的话可能会出很多问题,例如在外部使用时,被重新赋值(=),而使得之前所有的委托函数消失。

如果我们不想暴露这种委托属性,event就登场了,它会保护delegate委托属性,并且只暴露“+=”和“-=”操作符。注意这里说的是暴露,因为在类内部操作其他操作符例如“=”还是有效的。并且暴露的访问等级与定义委托属性的访问等级一致。

多说无益,上示例:

 public class EventAndDelegate
 {
     public delegate void SayHello(string sth);
     public event SayHello delegateSayHello;
     public EventAndDelegate() { }
     public void SayIt(string str)
     {
         if (delegateSayHello != null)
         {
             delegateSayHello(str);
         }
     }
     public static void Say1(string str)
     {
         Console.WriteLine("this is say 1 ... " + str);
     }
     public static void Say2(string str)
     {
         Console.WriteLine("this is say 2 ... " + str);
     }
 }

在Main函数中使用:

static void Main(string[] args)
{
    EventAndDelegate ead = new EventAndDelegate();
    ead.delegateSayHello += EventAndDelegate.Say1;
    // ead.delegateSayHello = EventAndDelegate.Say2; // 编译错误
    ead.SayIt("skii");
    Console.ReadKey();
}

输出内容就是Say1函数的内容,不再贴出了。只需要注意:event定义的delegate委托,只会暴露+=和-=就行了。

结论
event关键字算是给delegate专做的封装性优化,保证其封装的合理性。但是其实我们也可以通过Java的标准封装模式进行属性封装。不过微软既然给了,就也多用用吧。


delegate & event

在上述delegate和event关键字的概念有所了解之后,就可以引出最后的内容了:EventArgs

标准化事件
我们可以出:委托可以定义成多种多样的形式,包括返回参数类型和输入参数类型。其实就是最主要的函数输入和函数输出。那么实际上,如果我们想要多种多样的事件的时候,就要定义很多种不用的委托类型,这会相当难以维护。我们再看看微软全家桶的事件,不论是windowsform、wpf还是ASP.Net,事件的方式基本都是:

protected void FunctionName(object sender, EventArgs e)

实际上,这种方式很讨喜,为什么这么说呢?

  1. 它没有返回值,也就是说可以提起裤子就走人。
  2. 他有一个sender参数表示事件发送者,以及一个EventArgs类型的事件参数,这个参数可以包括处理事件函数所需的参数。

这就引出了本小节的核心类:EventArgs
由于大部分的事件的参数接收都是EventArgs类型的,它基本上是基类,因此我们可以使用is或者as运算符进行区分和转换,变成我们需要使用的类型。这就使得EventArgs具有很高的扩展性。

于是这种设计模式基本上就可以涵盖大部分的订阅者模式类型的设计模式了。

这篇文章讲的还不错的,可以看看其中的示例,我只是把我的理解记录下来,并没有很详细地进行展开,所以想看详细示例的话


结论

一直以为event和delegate是两套东西,现在看来是同一套东西,也明白了委托和事件的关系,基本上还是靠一手委托,所以主要记住委托的用法就好了。然后event相关的概念,目前在工作上还没有碰到过,但是结构和设计模式很好看,值得学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值