拋開書本,為什么出現了事件,事件與委托有什么淵源?


拋開書本,為什么出現了事件,事件與委托有什么淵源?
博文都是源於自己的理解,文字間流露的是不是書本那樣官方的語言,望大家喜歡。

朋友,如果你對委托沒什么概念,請參閱我的上一篇博文《拋開書本,為什么需要委托,它的出現成就了什么?》

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框架的標准 事件 今天來不及發布了。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM