1. 程式人生 > >委託-非同步呼叫-泛型委託-匿名方法-Lambda表示式-事件

委託-非同步呼叫-泛型委託-匿名方法-Lambda表示式-事件


1. 委託

類是物件的抽象,而委託則可以看成是函式的抽象。一個委託代表了具有相同引數列表和返回值的所有函式。

    class Program
    {
        delegate int CalculateDelegate(int a, int b);

        int add(int a, int b)
        {
            return a + b;
        }

        static void Main(string[] args)
        {
            CalculateDelegate d = new Program().add;
            //CalculateDelegate d = new CalculateDelegate(new Program().add);
            Console.WriteLine(d(1, 2));
            Console.ReadKey();
        }
    }


委託作為引數,在C#中非常常見。比如執行緒的建立,需要給一個ThreadStart或者ParameterizedThreadStart委託作為引數,而線上程執行的時候,將這個引數所指代的函式用作執行緒執行體。再比如:List<T>型別的Find方法的引數也是一個委託,它把“怎麼去查詢”或者說“怎麼樣才算找到”這個問題留給了開發人員。這有點像模板模式。

委託作為返回值一般會用在“根據不同情況決定使用不同的委託”這樣的情形下。這有點像工廠模式。

2. 非同步呼叫

非同步通過委託來完成。.net使用delegate來"自動"生成的非同步呼叫是使用了另外的執行緒(而且是執行緒池執行緒)。

class Program    
{    
    static TimeSpan Boil()    
    {    
        DateTime begin = DateTime.Now;    
        Console.WriteLine("水壺:開始燒水...");    
        Thread.Sleep(6000);    
        Console.WriteLine("水壺:水已經燒開了!");    
        return DateTime.Now - begin;    
    }    
    delegate TimeSpan BoilingDelegate();    
   
    static void Main(string[] args)    
    {    
        Console.WriteLine("小文:將水壺放在爐子上");    
        BoilingDelegate d = new BoilingDelegate(Boil);    
        IAsyncResult result = d.BeginInvoke(BoilingFinishedCallback, null);    
        Console.WriteLine("小文:開始整理家務...");    
        for (int i = 0; i < 20; i++)    
        {    
            Console.WriteLine("小文:整理第{0}項家務...", i + 1);    
            Thread.Sleep(1000);    
        }    
    }    
   
    static void BoilingFinishedCallback(IAsyncResult result)    
    {    
        AsyncResult asyncResult = (AsyncResult)result;    
        BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate;    
        Console.WriteLine("(燒水一共用去{0}時間)", del.EndInvoke(result));    
        Console.WriteLine("小文:將熱水灌到熱水瓶");    
        Console.WriteLine("小文:繼續整理家務");    
    } 
}   


EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke會使得呼叫執行緒阻塞,直到非同步函式處理完成。EndInvoke呼叫的返回值也就是非同步處理函式的返回值。

3. 泛型委託

[Serializable]  

publicdelegatevoid EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs: EventArgs; 

class IntEventArgs : System.EventArgs    
{    
    public int IntValue { get; set; }    
    public IntEventArgs() { }    
    public IntEventArgs(int value)     
    { this.IntValue = value; }    
}    
   
class StringEventArgs : System.EventArgs    
{    
    public string StringValue { get; set; }    
    public StringEventArgs() { }    
    public StringEventArgs(string value)     
    { this.StringValue = value; }    
}    
   
class Program    
{    
    static void PrintInt(object sender, IntEventArgs e)    
    {    
        Console.WriteLine(e.IntValue);    
    }    
   
    static void PrintString(object sender, StringEventArgs e)    
    {    
        Console.WriteLine(e.StringValue);    
    }    
   
    static void Main(string[] args)    
    {    
        EventHandler<IntEventArgs> ihandler =     
            new EventHandler<IntEventArgs>(PrintInt);    
        EventHandler<StringEventArgs> shandler =     
            new EventHandler<StringEventArgs>(PrintString);    
   
        ihandler(null, new IntEventArgs(100));    
        shandler(null, new StringEventArgs("Hello World"));    
    }    
}


4. 匿名方法

只需要給出方法的引數列表(甚至也可以不給)以及方法具體實現,而不需要關心方法的返回值,更不必給方法起名字。最關鍵的是,只在需要的地方定義匿名方法,保證了程式碼的簡潔。比如用於委託作為函式引數。

class Program    
{    
    static void Main(string[] args)    
    {    
        List<string> names = new List<string>();    
        names.Add("Sunny Chen");    
        names.Add("Kitty Wang");    
        names.Add("Sunny Crystal");    
   
        List<string> found = names.FindAll(    
            delegate(string name)    
            {    
                return name.StartsWith("sunny",    
                    StringComparison.OrdinalIgnoreCase);    
            });    
   
        if (found != null)    
        {    
            foreach (string str in found)    
                Console.WriteLine(str);    
        }    
    }  
}


5. Lambda表示式

從委託的角度來看,Lambda表示式與匿名方法沒有區別。Lambda表示式的定義方式為:“([引數列表]) => 表示式”。

class Program    
{    
    static void Main(string[] args)    
    {    
        List<string> names = new List<string>();    
        names.Add("Sunny Chen");    
        names.Add("Kitty Wang");    
        names.Add("Sunny Crystal");    
   
        List<string> found = names.FindAll    
            (    
            // Lambda Expression Implementation    
            name => name.StartsWith(    
                "sunny",     
                StringComparison.OrdinalIgnoreCase)    
            );    
   
        if (found != null)    
        {    
            foreach (string str in found)    
                Console.WriteLine(str);    
        }    
    }    
} 

6. 事件

事件由委託定義。事件的觸發方只需要確定好事件處理函式的簽名即可。也就是說,觸發方只需要定義在事件發生時需要傳遞的引數,而在訂閱方,只需要根據這個簽名定義一個處理函式,然後將該函式“繫結”到事件列表,就可以通過簽名中的引數,對事件做相應的處理。