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);
}

 

看到了吧,就是委託!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章