(語法基礎)委托學習總結(三)泛型委托


之前,我們學習總結了委托這個概念,也闡述了委托,匿名方法,lambda表達式三者之間的關系,那么今天再來繼續學習委托更深層次的東西:泛型委托,什么是泛型,這個概念我也會在之后做出總結,這里不做很深層次的討論,重點是討論泛型和委托如何配合使用,其實泛型這個概念在這里也不會對我們對委托的理解有太大的影響,我們只要大概知道泛型就是一種動態的類型,它在使用時可以代表任意類型,下面我們再來回顧一下我們是如何定義普通委托的:

public delegate int 委托名(int a, int b);

這是委托的定義,它的定義有這幾個特點,(1)可以用訪問修飾符修飾。(2)delegate關鍵字。(3)有返回值和參數。

我們之前也說了,委托是一種類型,與之對應的方法必須和它具有相同的簽名,即相同的參數個數,相同的參數類型和相同的返回值類型。我們回顧了普通委托之后再來看一下泛型委托的定義:

public delegate T 委托名<T>(T a, T b);

與之前不同的是,我們把int類型變成了萬能的T類型,這樣寫的好處是什么呢?
可以想象,我們之前寫了這樣一個方法來處理加減乘除不同的計算方法:

    static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }    

仔細的你會發現我們封裝的這個方法有很大的局限性,假如我們某天要計算Double,float小數類型或者其他類型的加減乘除時,我們是不是又不得不重載多個不同參數類型的Calculate方法,即:

    static void Calculate(Expression ex, double a, double b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }

    static void Calculate(Expression ex, float a, float b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }

這樣的話是不是代碼又有重復了,那假設又幾千種不同的類型要去計算呢?我們能不能只寫一個方法就處理不同類型的加減乘除呢?這時,C#里有一個重要的工具:泛型的作用就體現出來了,我們可以把委托和方法定義成泛型的。代碼如下:

    public delegate T Expression<T>(T a, T b);
    class Program
    {
        static void Main(string[] args)
        {
            Expression<int> add = (a, b) => a + b;
            Calculate(add, 10, 25);
            Console.ReadKey();
        }
        static void Calculate<T>(Expression<T> ex, T a, T b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }     
    }

我們只需在聲明委托Expression<>時,為委托定義int類型就可以了,假如有一天,我要定義double類型,同理只需把Expression<int>換成Expression<double>即可,這樣寫是不是既節省了代碼,又讓Calculate方法的靈活性變高了。不管是lambda表達式還是泛型,微軟可謂把DRY(Don't-repeat-yourself)原則發揮的淋漓盡致,其實微軟早已為我們定義好了一套泛型委托供我們使用,以免我們在自己使用時還繁瑣重復的去定義它,他們分別是Action,Func和Predicate

這是我在資料上摘取的這幾個委托的區別:

(1). Action

       Action是無返回值的泛型委托。

 

   Action 表示無參,無返回值的委托

 

   Action<int,string> 表示有傳入參數int,string無返回值的委托

 

   Action<int,string,bool> 表示有傳入參數int,string,bool無返回值的委托

 

       Action<int,int,int,int> 表示有傳入4個int型參數,無返回值的委托

 

   Action至少0個參數,至多16個參數,無返回值。

 (2). Func

   Func是有返回值的泛型委托

   Func<int> 表示無參,返回值為int的委托

   Func<object,string,int> 表示傳入參數為object, string 返回值為int的委托

   Func<object,string,int> 表示傳入參數為object, string 返回值為int的委托

   Func<T1,T2,,T3,int> 表示傳入參數為T1,T2,,T3(泛型)返回值為int的委托

   Func至少0個參數,至多16個參數,根據返回值泛型返回。必須有返回值,不可void

(3). Predicate

   predicate 是返回bool型的泛型委托

   predicate<int> 表示傳入參數為int 返回bool的委托

   Predicate有且只有一個參數,返回值固定為bool

一般的需求下,我們就使用微軟定義的委托就足夠了,這樣減少了我們對委托的重復定義,可能有部分初學者見到Func<>,Action<>這樣的代碼肯定會很懵比,這只是你對新東西陌生罷了,多結合實例敲幾遍,自然就會用了,它們其實就是微軟封裝定義好了的委托,沒有什么特別的。我們上面的代碼也可以這樣寫:

    class Program
    {
        static void Main(string[] args)
        {
            Func<int,int,int> add = (a, b) => a + b;
            Calculate(add, 10, 25);
            Console.ReadKey();
        }
        static void Calculate<T, Y, U>(Func<T, Y, U> ex, T a, Y b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

這樣寫用Func就省去了定義委托這一步。

同樣,其實在我們的webform,winform框架中,微軟也給我們規范了一個委托的定義:

delegate void EvenHandler(object sender, EventArgs e);

都知道上面的object類是所有類型的基類,那EventArgs類呢?它其實就是所有包含事件數據類的基類

 


免責聲明!

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



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