ASP.NET談委託和事件

iDotNetSpace發表於2008-09-16

一、委託的定義:
《高階漢語大詞典》中是如下解釋的:託付給別的人或機構辦理。要說生活中的意思其實大家都能理解,無非是“當某人(機構)需要完成一件自己不能或不應該完成的事情的時候,此人(機構)物色一個合適的且有能力完成此事的人選,然後提供必要的資訊,將此事委託給物色到的人(機構)來完成。” C#中的委託是一種引用方法的型別,一旦為委託分配了方法,委託將與該方法具有完全相同的行為,委託方法的使用可以像其他任何方法一樣具有引數和返回值。委託物件能被傳遞給呼叫該方法引用的程式碼而無須知道哪個方法將在編譯時被呼叫。委託是函式的封裝,它代表一“類”函式。他們都符合一定的簽名:擁有相同的引數列表、返回值型別。同時委託也可以看作是對函式的抽象,是函式的“類”。此時,委託例項代表一個具體的函式。委託應該和類同屬一個層面,使用起來也很象一個類。我們先來看一個委託使用的例項:

ASP.NET談委託和事件
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic delegate void PrintHandler(string str);    // 宣告委託型別

    
public class PrintStr
    {               
        
public void CallPrint(string input)
        {
            Console.WriteLine(input);
        }
        
    }
static void Main(string[] args)
{
            PrintStr myPrinter 
= new PrintStr();
            PrintHandler myHandler 
= null;
            
// 將委託連結到方法,來例項化委託
            myHandler += new PrintHandler(myPrinter.CallPrint); 

            
if (myHandler != null)
                myHandler(
"Hello World!");    // 呼叫委託,相當於匿名呼叫委託所連結的方法
            myHandler -= new PrintHandler(myPrinter.CallPrint);
            
if (myHandler == null)
                Console.WriteLine(
"myHandler==null");
            Console.Read();
}

 

得到的結果為
Hello World!
myHandler==null

 

二、委託的特點
1、一個委託物件可以搭載多個方法。
2、一個委託物件搭載的方法並不需要屬於同一個類,但所搭載的方法必須具有相同的原形和形式。
3、委託的例項將代表一個具體的函式

 

三、為什麼要使用委託
1、更加靈活的方法呼叫。我們先舉一個例子:

ASP.NET談委託和事件
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtnamespace delegateEvent
{
  
public class BackupUtil
  {
    
string _buFolder = "c:\\backup\\";
    
    
//declare the delegate type
    public delegate bool BackupFiles(string folder);

    
public BackupFiles Backup;

    
public BackupUtil(string backupType)
    {
      
switch (backupType)
      {
        
case "EXE"  :
          Backup 
= new BackupFiles(BackupOnlyEXE);
          
break;
        
case "Folder" :
          Backup 
= new BackupFiles(BackupCurrentFolder);
          
break;
        
case "Today"  :
          Backup 
= new BackupFiles(BackupAccessedToday);
          
break;
      }

    }
    
private bool BackupOnlyEXE(string folder)
    {
      
foreach(string file in Directory.GetFiles(folder, "*.exe"))
      {
        FileInfo fi 
= new FileInfo(file);
        File.Copy(fi.FullName, _buFolder 
+ fi.Name);
      }
      
return true;
    }
    
private bool BackupCurrentFolder(string folder)
    {
      
foreach(string file in Directory.GetFiles(folder))
      {
        FileInfo fi 
= new FileInfo(file);
        File.Copy(fi.FullName, _buFolder 
+ fi.Name);
      }
      
return true;
    }

    
private bool BackupAccessedToday(string folder)
    {
      
foreach (string file in Directory.GetFiles(folder))
      {
        
if (File.GetLastAccessTime(file).Date == DateTime.Now.Date)
        {
          FileInfo fi 
= new FileInfo(file);
          File.Copy(fi.FullName, _buFolder 
+ fi.Name);
        }
      }
      
return true;
    }

  }
}
 
static void Main(string[] args)
 {
      BackupUtil bu 
= new BackupUtil("Today");
      
bool ret = bu.Backup("c:\\test\\");
      Console.WriteLine(ret.ToString());
}

 

這個例子中客戶端會根據不同的情況對檔案進行備份

2、用於非同步回撥
由於例項化委託是一個物件,所以可以將其作為引數進行傳遞,也可以將其賦值給屬性。這樣方法就可以將一個委託作為引數來接受,並且以後可以呼叫該委託。這稱為非同步回撥,是在較長的程式完成後用來通知呼叫方的常用方法,以這種方式使用委託時,使用委託的程式碼無需瞭解有關使用方法的實現方面的任何資訊。
我們假設這樣一個場景,我們希望有這樣一個函式,對一個整型陣列進行過濾,而過濾得條件在編寫函式時還不知道,直到使用這個函式的時候可以根據當前的情況編寫過濾條件函式,我們使用委託實現如下:

ASP.NET談委託和事件
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic delegate bool IntFilter(int i);
public class Common
    {
        
public static int[] FilterArrayOfInts(int[] ints, IntFilter filter)
        {
            ArrayList aList 
= new ArrayList();
            
foreach (int i in ints)
            {
                
if (filter(i))
                {
                    aList.Add(i);
                }
            }
            
return ((int[])aList.ToArray(typeof(int)));
        }
    }
public class Application
    {
        
public static bool IsOdd(int i)
        {
            
return ((i & 1== 1);
        }
    }
static void Main(string[] args)
        {
            
int[] nums = { 12345678910 };
            
int[] oddNums = Common.FilterArrayOfInts(nums, Application.IsOdd);
            
foreach (int i in oddNums)
                Console.WriteLine(i);
        }

 

結果為:

1
3
5
7
9

 3、多執行緒程式設計中使用委託來指定啟動一個執行緒時呼叫的方法

ASP.NET談委託和事件
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic static void ThreadProc() 
{
        
for (int i = 0; i < 10; i++
    {
            Console.WriteLine(
"ThreadProc: {0}", i);
            
// Yield the rest of the time slice.
            Thread.Sleep(0);
        }
}
public static void Main() 
{
    Thread t 
= new Thread(new ThreadStart(ThreadProc));
}

 

4、C#中的事件模型。用他們指明處理給定事件的方法。
下面我們詳細來介紹事件。
四、事件
事件允許型別(或者型別的例項)在某些特定事情發生的時候通知其他物件。
例如button類定義了一個名為click的事件,當buton物件被點選時,應用程式中的一些物件可能希望能夠收到一個通知,並執行一些動作。但問題是當我們編寫button類的時候並不知道到底要做什麼,到底要呼叫哪些方法,我們只要在使用button的場景才知道到底應該在按下button時做些什麼,基於這樣的情況,我們想起了委託,我們先在button類中定義一個委託,然後在使用button的相應場景註冊這個委託即可,似乎用委託就解決了這個問題了,那事件還有什麼用呢,也就是說委託和事件的區別在哪裡呢,其實事件就是一種特殊的委託,使用事件委託的型別,必須使用+=進行註冊而不能用=,這樣做的原因是事件中已經註冊的方法不希望被新註冊的方法覆蓋掉。微軟為使用事件定義了一個模式。
事件模式由以下五步組成:
1、定義一個型別用於儲存所有需要傳送給事件通知接受者的附加資訊(繼承於System.EventArgs)
2、定義一個委託型別,用於指定事件觸發時被呼叫的方法型別
3、定義一個事件成員
4、定義一個受保護的虛方法,負責通知事件的登記物件
5、定義一個方法,將輸入轉化為期望的事件
我們這裡舉一個發Email的時候觸發事件的例子:

ASP.NET談委託和事件
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic class MailManager
    {

        
//1、定義一個型別用於儲存所有需要傳送給事件通知接受者的附加資訊(繼承於System.EventArgs)

        
public class MailMsgEvernArgs : EventArgs
        {
            
public MailMsgEvernArgs( string from,string to,string subject,string body)
            {
                
this.from = from;
                
this.to = to;
                
this.subject = subject;
                
this.body = body;
                
            }
            
public readonly string from,to,subject,body;
        
        }

        
//2、定義一個委託型別,用於指定事件觸發時被呼叫的方法型別

        
public delegate void MailMsgEventHandler(object sender,MailMsgEvernArgs args);

        
//3、定義一個事件成員

        
public event MailMsgEventHandler MailMsg;

        
//4、定義一個受保護的虛方法,負責通知事件的登記物件

        
protected virtual void OnMailMsg(MailMsgEvernArgs e)
        {
            
if(MailMsg!=null)
                MailMsg(
this,e);
        }
        
//5、定義一個方法,將輸入轉化為期望的事件
        public void SimulateArrivingMsg(string from,string to,string subject,string body)
        {
            MailMsgEvernArgs e 
= new MailMsgEvernArgs(from,to,subject,body);
            OnMailMsg(e);
        }
    }
static void Main(string[] args)
{    
    MailManager mm 
= new MailManager();
        mm.MailMsg 
+= new MailManager.MailMsgEventHandler(mm_MailMsg);
        mm.MailMsg 
+= new MailManager.MailMsgEventHandler(mm_MailMsg1);
        mm.SimulateArrivingMsg(
"中國""美國""subject""body");
}
private static void mm_MailMsg(object sender, MailManager.MailMsgEvernArgs args)
{

            Console.WriteLine(args.from);
            Console.WriteLine(args.to);
}
private static void mm_MailMsg1(object sender, MailManager.MailMsgEvernArgs args)
{

            Console.WriteLine(args.subject);
            Console.WriteLine(args.body);
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-448572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章