1. 程式人生 > >泛型委託

泛型委託

之前,我們學習總結了委託這個概念,也闡述了委託,匿名方法,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);



https://www.cnblogs.com/ruanraun/p/6044477.html