抛开书本,为什么出现了事件,事件与委托有什么渊源?

抛开书本,为什么出现了事件,事件与委托有什么渊源?
博文都是源于自己的理解,文字间流露的是不是书本那样官方的语言,望大家喜欢。

朋友,如果你对委托没什么概念,请参阅我的上一篇博文《抛开书本,为什么需要委托,它的出现成就了什么?》

http://www.cnblogs.com/IAmBetter/archive/2012/02/08/2342443.html

 

由于时间紧,博文没有涉及到 .net框架 标准式的事件,明天会写出来。

 

思路:委托---->事件存在的价值---->事件的进化---->总结

1.参照上一篇博文
代码如下:
山寨版委托:

View Code
public delegate void CYDL(string name);
class Program
{
static void Main(string[] args)
{
CYDL one = new CYDL(Dancing);
one += new CYDL(Singing);
PersonCY("Mr.w",one);
}
static void PersonCY(string name,CYDL one)
{
one(name);
}
static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞",name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌",name);
}
}



上面是一个简单的案例,也不是正规的委托:
正规版:

View Code
public delegate void CYDL(string name);
class Program
{
static void Main(string[] args)
{

CYDL one = new CYDL(Dancing);
one += new CYDL(Singing);
one("Mr.w");
}

static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞",name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌",name);
}
}



思考一个问题:我们学习到现在,几乎很少在Main函数内部 从一个类内部调用这个类的另一个方法,是吧?这也太有损面向对象这个概念了。

现在我们把 各个方法放进不同的类里,然后再利用委托调用
代码如下:
 

View Code
public delegate void CYDL(string name);
class Person
{
public void PersonCY(string name, CYDL one)
{
one(name);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.PersonCY("Mr.w",Dancing);//这样直接代入方法也是可以的,编译器会自动委托类型

}

static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞", name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌", name);
}
}



<注意>
分析下:为什么person.PersonCY("Mr.w",Dancing);//这样直接代入方法也是可以的,编译器会自动委托类型?
利用IL指令查看:
 


1.发现ldftn指令 把 Dancing()方法在Load堆内的地址压入了堆栈。
2.newobj 发现 这里新建CYDL 委托类型实例
即:这里是隐式转换成了 委托类型的。

好了,继续进入正题,

View Code
 static void Main(string[] args)
{
Person person = new Person();
CYDL one = Dancing;
one += Singing;
person.PersonCY("Mr.w",one);

}



好了,这样就符合我们的一般的模式了,即:类的对象调用方法。
缺点:没当 实例化一个对象,那么就有可能要改变 委托变量的绑定方法,或者重新 声明一个 委托变量two,这样是不是太麻烦了。
面向对象的有一个封装的概念,让我们把  这个委托变量封装到类内部,让对象可以调用。

进化1:

View Code
public delegate void CYDL(string name);
class Person
{
public CYDL one;

public void PersonCY(string name, CYDL one)
{
one(name);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.one = Dancing;
person.one += Singing;
person.PersonCY("Mr.w",person.one);

}

static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞", name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌", name);
}
}



缺点:细心的朋友可能发现了,调用PersonCY(),重复带入了one的委托变量。

进化2:
即:
 

View Code
public delegate void CYDL(string name);
class Person
{
public CYDL one;

public void PersonCY(string name)
{
if (one != null)//判断委托是否绑定了方法
{
one(name);
}
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.one = Dancing;
person.one += Singing;
person.PersonCY("Mr.w");
}

static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞", name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌", name);
}
}



但是我们知道,对于字段来说,委托类型的变量也是字段,我们通常是在访问权限上是private私有的。问题来了,如果设置了委托变量为私有的访问权限,那么
我们如何给委托绑定方法呢?(在其他非继承类中无法调用这个变量)
对于以往,我们对于字段的处理是使用 属性,可是 委托有没有类似于属性的东西?


进化3:事件出场
如下:
 

View Code
public delegate void CYDL(string name);
class Person
{
public event CYDL one;//就这么简单,加个event

public void PersonCY(string name)
{
if (one != null)//判断委托是否绑定了方法
{
one(name);
}
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
//person.one = Dancing; 这里是赋值操作,会报错
person.one += Singing;
person.PersonCY("Mr.w");
}

static void Dancing(string name)
{
Console.WriteLine("{0}会跳舞", name);
}
static void Singing(string name)
{
Console.WriteLine("{0}会唱歌", name);
}
}



event实质就是声明一个私有的委托,使得委托封装。
所以对于一个私有地段,person.one = Dancing; 肯定会报错。
查看IL代码:

 


变量one:private class DL.CYDL 说明自动生成了一个私有的变量。所以无法使用“=”赋值。
上图可以看出:一个委托会注册和注销方法,本质是在加载的时候加载了add_one和remove_one方法。
本质 委托就是一个类,当执行public delegate void CYDL(string name);的时候就会生产一个完整的类。

以上就是简单的事件的概念,可能有朋友会问 怎么和winform中的事件不一样啊?

进化4:像样的事件
事件有2个用户:被监视者 监视者,事件必须本身触发。
可能难以理解,我举个例子:
1.被监视者如果发生某种改变,监视者会根据这个改变作出相应的对策
2.那么监视者如何知道 被监视者改变了呢,这就是注册事件。
面向对象的设计 有 继承关系 聚合关系 依赖关系,一般OBServer模式 就是耦合度低的依赖关系。

很形象的比如为 微博,我是博主,你们都订阅我,我发布新的微博信息了,你们就都收到了我的信息,然后对我的信息作出回应,如:转发,评论等。

View Code
 class 微博
{
public delegate void 委托();
public event 委托 事情;
private int 数字;
public void 数到10()
{
for (int i = 1; i < 100; i++)
{
数字 = i;//当我在博客上数到10的时候,就告诉收听我的人

if (事情 != null)//判断是否有博友收听我的微博
{
if (数字 == 10)
{
事情();//就触发收听我的人的方法
}
}
}

}
}

class 博友1
{
public void 转发()
{
Console.WriteLine("我知道你数到10了,我抓发你的微博");
}
}

class 博友2
{
public void 评论()
{
Console.WriteLine("我也知道你数到10了,我评论了你的微博");
}

}
上面是服务端,如何触发呢?
请看下列代码:
class Test
{
static void Main()
{
微博 博主 = new 微博();
博友1 one = new 博友1();
博友2 two = new 博友2();
博主.事情 +=new 微博.委托(one.转发);
博主.事情 += new 微博.委托(two.评论);

博主.数到10();

}
}

总结:技术有限,有错大家指正。博文形象易懂。.net框架的标准 事件 今天来不及发布了。





posted @ 2012-02-08 15:39  Anleb  阅读(3025)  评论(21编辑  收藏  举报