委托和事件的一些理解笔记

DELEGATE

delegate可以理解为一种为方法而设立的变量类型;

delegate是一种类型,首先要做的是对委托类型的声明 

public delegate void DoSomethingHandler(string target);

然后以此类型声明一个委托变量

DoSomethingHandler DoSomething;

然后可以根据需要给委托变量赋值

public void Kill(string target)
{
//some scripts
}
public void Save(string target)
{
//some scripts
}
DoSomething=kill;
DoSomething+=Love;

注意可以赋值的对象必须和delegate声明的委托变量具有同样的特征,也就是同样的参数值和返回值。委托变量可以同时赋予多个值,在执行时依次执行变量内所有的方法,这一点和普通变量相异; 在给delegate赋值时,“=”是赋值的语法,“+=”是绑定的语法,如果第一次赋值就用+=,将出现“使用了未赋值的局部变量”的编译错误。

EVENT

事件的声明

public delegate void DoSomethingHandler(string target);
public event DoSomethingHandler DoSomething;

在声明了委托类型之后,相比于声明委托变量时,多了一个event的修饰词。

实际上,事件即为封装后的委托变量,封装的目的是为了让委托变量拒绝所处类之外的任何调用。

引用一段代码,出处: http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-Advanced.aspx

class Program {
    static void Main(string[] args) {
        Publishser pub = new Publishser();
        Subscriber sub = new Subscriber();
        
        pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);
        pub.DoSomething();          // 应该通过DoSomething()来触发事件
        pub.NumberChanged(100);     // 但可以被这样直接调用,对委托变量的不恰当使用
    }
}

// 定义委托
public delegate void NumberChangedEventHandler(int count);

// 定义事件发布者
public class Publishser {
    private int count;
    public NumberChangedEventHandler NumberChanged;         // 声明委托变量
    //public event NumberChangedEventHandler NumberChanged; // 声明一个事件

    public void DoSomething() {
        // 在这里完成一些工作 ...

        if (NumberChanged != null) {    // 触发事件
            count++;
            NumberChanged(count);
        }
    }
}

// 定义事件订阅者
public class Subscriber {
    public void OnNumberChanged(int count) {
        Console.WriteLine("Subscriber notified: count = {0}", count);
    }
}

在这里如果将声明的委托变量更改为事件,那么pub.NumberChanged(100) 这里就会编译错误,这是因为在此处(声明event类型变量的类外)想要直接调用event变量,而event变量对外封闭。与此相反委托变量则没有这个限制,这就是event 与delegate变量之间的主要区别和设计初衷,event相较于delegate封装性更好,事件仅仅是供其他类型订阅,而客户端不能直接触发事件(语句pub.NumberChanged(100)无法通过编译),事件只能在事件发布者Publisher类的内部触发(比如在方法pub.DoSomething()中),换言之,就是NumberChanged(100)语句只能在Publisher内部被调用。再引用一句:就好像如果我们要定义一个数字类型,我们会使用int而不是使用object一样,给予对象过多的能力并不见得是一件好事,应该是越合适越好。尽管直接使用委托变量通常不会有什么问题,但它给了客户端不应具有的能力,而使用事件,可以限制这一能力,更精确地对类型进行封装。

PS:既然event类型的变量对外封闭,那么声明事件的时候修饰符(public,private)的作用是什么呢?

查看event的内部代码,有两个方法对外开放,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委托类型的方法和取消注册。对应的就是外部访问时所用的“+=”“-+”绑定和解绑修饰符,因此事件变量在类外部访问只可以绑定和解绑方法(+=,-=),不可以直接赋值(=);而声明事件时的修饰符(public,private)则修饰这两个方法(+=,-=)的访问权限。

 

posted @ 2017-03-10 20:36  丁香与醋栗  阅读(182)  评论(0编辑  收藏  举报