解C#中的代理和事件(一)
突然寫這篇文章,真的有點,是在做作的感覺,我想這并不是什么,難以
理解的東西,事實上,很多人都寫過,而且,我保證至少不比我寫的差.可是
還是覺得有必要提出來.因為要去正確的理解代理和事件是很有趣的,也是
很必要的.那么好吧,下面我就來講講,它們之間的關系.當然還會有些例子.
首先我想說說有關事件.事件顧名思義當然是windows程序收到的消息.
那么我舉幾個有關事件的例子,如鼠標移動.按下.之類的都是.那么代理呢?
很多人都說它看上去,就是想是一個受托管的函數指針.我覺得這種說法很
正確,事實如此.在MSDN上,我們經??梢钥吹?有關代理的"多路廣播"這個詞
我覺得不錯,可是不好理解.但我會在下面詳細講解的.
代理:(有的書上也翻譯成指代或委托.英文是這樣一來的"Delegate")
我想很多剛接觸C#的人,都會對代理產生興趣的.事實上也是如此,不了解它,你就沒辦法
來做windows程序.和傳統意義上的函數指針有所不同的是,代理在C#中是一種類型,這樣
它看上去,更安全也,更符合OO精神.代理實際上所做的工作就是通過引用把函數包裹起來
并使函數有一個有效的返回值.不知道我這樣說是否好理解.那么我舉個例子,你去建造房子.
很顯然,我是在說你所做的事情.那么建造房子就是代理,它指代了,你要做的事情,可是它并
沒有去做任何事情,事實上是,在建造房子這個工作里,你做了,那么結果是什么?當然是建立
一座房子.是的,建造房子就是代理,而如何建造房子則是函數應該完成的工作.而建造的是什么樣
的房子,則是返回值.還記得,我曾經說過,代理是一種類型嗎?呵呵..我想你應該記得,因為,
那是很新穎的,至少當時我那么認為.好吧,讓我們來看看名稱空間System.Delagate,看見了嗎?那
就代理類.
舉個例子:
public delegate void GetString()//我申明了一個代理
現在我要用到它了如下;
int i=100;
GetString gs=new GetString(i.ToString);//這里我吧int的ToString方法
填入了一個代理中.看上去想構造函數.這就是常在書上看到的"名稱等效的,而
不是結構等效的",我想看到這兒你還是不明白.那么,我再來一個代理
如下:
float j=0.0001;
GetString gs=new GetString(j.ToString);//瞧見了,int的ToString方法
和float的ToString方法的結構是不一樣的,可是名稱和類型的返回值和
參數都一樣.現在,我想,你應該理解了吧.
可是,我們經常會在MSDN中看到,這樣的句子.單路代理和多路廣播.看上去,有點不好理解.
事實上,我開始看這樣的句子,是有點頭痛的.那么,我想例子是最好的解說方式.
Single Delegate:(單路代理)
從字面上,我們可以這樣來理解,這個代理只是單單代理了一個函數的工作.那么好吧,讓
我們來看看它是如何工作的.下面我就來定義一個這樣的代理:
public delegate bool Myfun(string str,int i)
現在我再來寫一個方法如下:
bool CompareStrToInt(string s,int i)
{
if(s.CompareTo(i.ToString())==0)
return true;
else
return false;
}
這個方法完成的工作很簡單對吧,只是比較字符而已.那么和代理有什么關系呢?還記得
我說的話嗎?代理就是在把動詞名詞化.代碼如下:
Myfun mf=new (CompareStrToInt);
string s="10000";
int i=10000;
ConSole.WriteLine("Value="+mf(s,i));
輸出結果:
Value=true
這就是單路代理.它只代理一個.好吧,也許你想看看復雜的例子,更有趣的在后面呢,
該是討論多路廣播的時候了.
多路廣播:
一個代理同時代理幾個方法.就是我們前面說到的那樣,你去建造房子,現在要不僅僅是
建造住宅,還的去建造花園等等其它建筑物.可是它們都是在建造房子,傳遞的參數也相同
返回值的類型也相同都是房屋.那么我們為什么不找一個代理人來完成這樣的任務呢?把
這些事物交由他一個人來完成不是可以節省我們很多的時間和金錢.是的我們可以那樣做
System.MulticastDelegate 實際上在.net framework中你還可以找到這個類,多路代理
MSDN上翻譯成多路廣播.事實上它還重載了操作符+=.其實多路廣播和單路代理在使用方法
上區別不大.你可以看下面的例子.
using System;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class MyClassDelegate
{
/// <summary>
/// The main entry point for the application.
/// </summary>
public delegate string IntDelegate(string s);
}
}
using System;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for MyImplementingClass.
/// </summary>
public class MyClass
{
public MyClass()
{
}
public static string WriteString(string s)
{
Console.WriteLine("Writing string");
return "null";
}
public static string logString(string s)
{
Console.WriteLine("loging string");
return "null";
}
public static string TransmitString(string s)
{
Console.WriteLine("Transmitting string");
return "null";
}
}
}
The Main class:
using System;
using System.Threading;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for Test.
/// </summary>
public class Test
{
public static void Main()
{
MyClassDelegate.StringDelegate
Writer,Logger,Transmitter;
MyClassDelegate.StringDelegate
myDelegate;
Writer=new
MyClassDelegate.StringDelegate(MyClass.WriteString);
/// calling Writer
Writer("hello i am Writer just acting like Single cast");
Logger=new MyClassDelegate.StringDelegate(MyClass.logString);
///calling Logger
Logger("hello i am Logger just acting like Single-cast");
Transmitter=new MyClassDelegate.StringDelegate(MyClass.TransmitString);
///calling Transmitter
Transmitter("hello i am Transmitter just acting like Single-cast");
///here mydelegate used the Combine method of System.MulticastDelegate
///and the delegates combine
myDelegate=(MyClassDelegate.StringDelegate)System.Delegate.Combine(Writer,Logger);
myDelegate("used Combine");
///here Transmitter is also added using the overloaded form of Combine
myDelegate+=Transmitter;
myDelegate("Using Overloaded Form");
///now using the Remove method
myDelegate=(MyClassDelegate.StringDelegate)System.Delegate.Remove(myDelegate,Writer);
myDelegate("Without Writer");
///overloaded Remove
myDelegate-=Transmitter;
myDelegate("Without Transmitter");
System.Threading.Thread.Sleep(2300);
}
}
}
(上面的例子是在一個國外網站上找到的,覺得不錯,就直接套用了.)
上面的例子重點是看那兩個已經重載的操作符."-="和"+=".通過上面的例子,你可以清楚的
看到多路廣播是如何一次代理多個方法的.當然你也可以刪除掉那些你不想要的用"-="操作
符就可以了.(那么我將在下一篇討論事件)
原文轉自:http://www.anti-gravitydesign.com