C#解惑2——Delegate,Action,Func,匿名方法,匿名委托,事件(轉)


一、委托Delegate

一般的方法(Method)中,我們的參數總是string,int,DateTime...這些基本的數據類型(或者沒有參數),比如

復制代碼
public void HelloWorld() 
{
    Console.WriteLine("Hello World!");
}
public void HelloWorld(string name) 
{
    Console.WriteLine("Hello ,{0}!", name);
}
復制代碼

但是有些時候,我們希望把一個方法本身當做參數傳遞給另一個方法,比如

myObject.callMethod(HelloWorld);

在沒有委托之前,這是一件極困難的事情,委托出現以后,這就是一件很容易的事情了,簡單點講:委托就是一種能把方法當做參數來使用的類型--當然這個定義跟官方的解釋比起來極不嚴密,但易於理解

要點:
1.委托是一種類型(跟string,int,double...一樣是.net的一種基本類型)
2.委托的定義必須與最終被調用的方法保持簽名一致

比如:下面代碼中的

delegate void D1(); 與 static void HelloWorld1(),我們拋開前面的類型關鍵字delegate與static,他們的簽名都是void X()
void D2(string myName);與void HelloWorld2(string name); void HelloWorld3(string name);它們的簽名格式都是 void X(string Y)

3.委托的好處之一在於可以保持簽名格式不變的情況下,動態調用不同的處理邏輯(即不同的方法)

想想系統控件中的Button類,系統並不知道按鈕按下去時到底會執行怎么樣的邏輯(點擊后的處理,每個項目可能都不一樣,完全由需求決定),但是我們知道每個Button都有一個Click(object sender, EventArgs e)這樣的東東,沒錯,就是委托(當然封裝成了另一種衍生類型event),就是這種設計保證了統一的格式,不管你實際開發中想如何處理點擊后的邏輯,只要按這個統一的簽名來就行了
完整代碼演示:

復制代碼
using System;
namespace ActionStudy
{
    class Program
    {
       
        delegate void D1();
        delegate void D2(string myName);


        static void Main(string[] args)
        {
            D1 d1 = new D1(HelloWorld1);
            d1();

            D2 d2 = new D2(HelloWorld2);
            d2("Jimmy");

            d2 = new D2(HelloWorld3);
            d2("楊俊明");            

            Console.Read();

        }

        static void HelloWorld1()
        {
            Console.WriteLine("Hello World!");
        }


        static void HelloWorld2(string name) 
        {
            Console.WriteLine("Hello,{0}!", name);
        }

        static void HelloWorld3(string name)
        {
            Console.WriteLine("你好,{0}!", name);
        }
    }
}
復制代碼

 二 、匿名方法(.net2.0開始支持)

在“一、委托Delegate”的演示代碼中,我們看到委托調用方法前,至少得先定義一個簽名相同的方法,然后才能由委托調用(哪怕是只有一行代碼的方法),好象有點煩哦,想偷懶,ok,沒問題

復制代碼
using System;
namespace ActionStudy
{
    class Program
    {

        delegate void D1();
        delegate void D2(string myName);


        static void Main(string[] args)
        {
            D1 d1 = delegate
            {
                Console.WriteLine("Hello World!");
            };
            d1();

            D2 d2 = delegate(string name)
            {
                Console.WriteLine("Hello,{0}!", name);
            };

            d2("Jimmy");


            d2 = delegate(string name)
            {
                Console.WriteLine("你好,{0}!", name);
            };

            d2("楊俊明");

            Console.Read();

        }
    }
}
復制代碼

運行效果完全相同,只是省去了方法的單獨定義部分

到了.net 3.0這種偷懶的作風更誇張,看下面的代碼(利用了Lambda表達式)

復制代碼
using System;
namespace ActionStudy
{
    class Program
    {

        delegate void D1();
        delegate void D2(string myName);


        static void Main(string[] args)
        {           

            D1 d1 = () => { Console.WriteLine("Hello World!"); };
            d1();

            D2 d2 = (string name) => { Console.WriteLine("Hello,{0}!", name); };
            d2("Jimmy");

            d2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
            d2("楊俊明");

            Console.Read();

        }
    }
}
復制代碼

運行效果仍然沒變,初次接觸者可能感覺很怪,其實我也覺得怪,不過很多大牛們都喜歡這樣用,所以至少還是要能看得懂,否則別人會說"你 Out了" :)
三、Action

Action的本質就是委托,看它的定義:

復制代碼
namespace System
{
    // 摘要:
    //     Encapsulates a method that takes no parameters and does not return a value.
    public delegate void Action();
}

namespace System
{
    // 摘要:
    //     Encapsulates a method that takes a single parameter and does not return a
    //     value.
    //
    // 參數:
    //   obj:
    //     The parameter of the method that this delegate encapsulates.
    //
    // 類型參數:
    //   T:
    //     The type of the parameter of the method that this delegate encapsulates.
    public delegate void Action<T>(T obj);
}
復制代碼

 當然,還有Action<T1,T2>乃至Action<T1,T2,T3,T4>參數個數從2到4的類型,不過定義都差不多

簡單點講,Action是參數從0到4,返回類型為void(即沒有返回值)的委托

復制代碼
using System;
namespace ActionStudy
{
    class Program
    {

        static Action A1;
        static Action<string> A2;
       


        static void Main(string[] args)
        {
            A1 = new Action(HelloWorld1);
            A1();

            A2 = new Action<string>(HelloWorld2);
            A2("Jimmy");

            A2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
            A2("楊俊明");

            A2 = delegate(string name) { Console.WriteLine("我就是委托,{0} 你說對嗎?", name); };
            A2("菩提樹下的楊過");          

            Console.Read();

        }


        static void HelloWorld1()
        {
            Console.WriteLine("Hello World!");
        }


        static void HelloWorld2(string name)
        {
            Console.WriteLine("Hello,{0}!", name);
        }

       
    }


   
}
復制代碼

四、Func

Func其實也是一個"托"兒,呵呵,不過這個委托是有返回值的。看下定義就知道了:

復制代碼
namespace System
{
    // 摘要:
    //     Encapsulates a method that has no parameters and returns a value of the type
    //     specified by the TResult parameter.
    //
    // 類型參數:
    //   TResult:
    //     The type of the return value of the method that this delegate encapsulates.
    //
    // 返回結果:
    //     The return value of the method that this delegate encapsulates.
    public delegate TResult Func<TResult>();
}

namespace System
{
    // 摘要:
    //     Encapsulates a method that has one parameter and returns a value of the type
    //     specified by the TResult parameter.
    //
    // 參數:
    //   arg:
    //     The parameter of the method that this delegate encapsulates.
    //
    // 類型參數:
    //   T:
    //     The type of the parameter of the method that this delegate encapsulates.
    //
    //   TResult:
    //     The type of the return value of the method that this delegate encapsulates.
    //
    // 返回結果:
    //     The return value of the method that this delegate encapsulates.
    public delegate TResult Func<T, TResult>(T arg);
}
復制代碼

同Action類似,Func的參數從1到5個,有5個不同的重載版本
代碼:

復制代碼
using System;
namespace ActionStudy
{
    class Program
    {
                
        static Func<string> F;
        static Func<DateTime, string> F2;      


        static void Main(string[] args)
        {
            F = new Func<string>(HelloWorld1);
            Console.WriteLine(F());

            F2 = new Func<DateTime, string>(HelloWorld2);
            Console.WriteLine(F2(DateTime.Now));

            Console.Read();

        }


        static string HelloWorld1()
        {
            return "Hello World!";
        }


        static string HelloWorld2(DateTime time)
        {
            return string.Format("Hello World,the time is {0}.", time);
        }
       
    }   
}
復制代碼

五、匿名委托

ok,如果你沒有暈的話,再來看一下匿名委托,其實這也是一種偷懶的小伎倆而已
看代碼說話:

//F = new Func<string>(HelloWorld1);

其實也可以簡寫成這樣:

F = HelloWorld1;          

//F2 = new Func<DateTime, string>(HelloWorld2);

其實也可以簡寫成這樣

F2 = HelloWorld2;

方法直接賦值給委托,這二個類型不同吧???

沒錯,你會發現編譯一樣能通過,系統在編譯時在背后自動幫我們加上了類似 “= new Func<...>”的東東,所以我們能偷懶一下下,這個就是匿名委托。

如果你細心的話,會發現我們在定義Button的Click處理事件時,通常是這樣的:

this.button1.Click += new EventHandler(button1_Click);

但有時候我們也可以寫成這樣:

this.button1.Click += button1_Click;

這其實就是匿名委托的應用. 

六、事件event

其實,這...還是個托兒!

我們來看下按鈕Click事件的定義

// 摘要:
//     Occurs when the control is clicked.
public event EventHandler Click;

繼續刨根問底,查看EventHandler的定義: 

復制代碼
using System.Runtime.InteropServices;

namespace System
{
    // 摘要:
    //     Represents the method that will handle an event that has no event data.
    //
    // 參數:
    //   sender:
    //     The source of the event.
    //
    //   e:
    //     An System.EventArgs that contains no event data.
    [Serializable]
    [ComVisible(true)]
    public delegate void EventHandler(object sender, EventArgs e);
}
復制代碼

 

看到了吧,就是委托!

轉載請注明來自菩提樹下的楊過http://www.cnblogs.com/yjmyzz/archive/2009/11/23/1608818.html


免責聲明!

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



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