委托和lambda表達式,Action和Func


1、為什么要用委托

我們為什么要有委托?任何東西存在即合理,不合理的也會被時間淘汰掉,委托既然存在肯定有存在的必要,我們來看一下什么時候可以用到委托。

接下來我們有個需求,就是調用一個方法,取出1-1000個數字中所有是10的倍數的數字

public static List<int> GetNum() {
    List<int> lst = new List<int>();
    //這個算法是最簡陋的,但是舉這個例子是最合適的
    for (int i = 1; i < 1000; i++)
    {
        if (i%10==0) {
            lst.Add(i);
        }
    }
    return lst;
}

這個很好寫,但是如果有一天,我們的需求變了,想取出1-1000個數字中所有是8的倍數的數字,那我們應該怎么寫?是不是只要將if里面的條件改為i%8==0就行了,但是有一點變動的話就修改方法,說明這個方法寫的並不好,如果方法很復雜的話修改也很艱難。可能有人會說在添加一個獲取是8的倍數的方法,這樣的話會增加數據冗余,也就是重復的內容。

如果我們可以傳遞方法的話,只要傳過來一個(有一個參數為int類型返回值為Boolean類型的方法),這個問題將不是問題

public static List<int> GetNum(有一個int類型的參數返回值為Boolean類型的方法) {
    List<int> lst = new List<int>();
    for (int i = 1; i < 1000; i++)
    {
        if (有一個int類型的參數返回值為Boolean類型的方法) {
            lst.Add(i);
        }
    }
    return lst;
}

是不是我們將想要獲取什么樣的數字這個操作來交給了調用者,無論調用者想獲取1-1000以內什么樣的數字都可以完成。但是這個方法的前提就是可以傳遞方法,這個時候我們就需要用到委托了。

2、委托如何使用

委托其實就是一個能夠指向方法的 指針,定義了一個委托就是定義了一個 類型

首先我們先來定義一個委托,也就是定義一個類型

//訪問修飾符  委托關鍵字  方法的返回值類型  要定義的類型名(參數1,參數2.....);
public delegate Boolean DelegateFunc(int x);

委托定義好了,也就是說我們已經定義好了一個DelegateFunc類型,這個類型的使用方法就和public class DelegateFunc{}寫了一個類是一樣的,因為都是定義了一個類型,既然大家都是類型,那用法肯定都是一樣的,我們先來看一下聲明普通的類型是如何聲明的

//類型 變量名 = 實例化一個Object類型的對象(構造函數有無參數)
Object obj = new Object();

而DelegateFunc既然也是我們定義好的一個類型,那用法自然一樣(因為構造函數需要參數,所以下面這樣寫是不對的,沒有傳入參數)

//類型       變量名 = 實例化一個DelegateFunc類型的對象(構造函數有無參數)
DelegateFunc func = new DelegateFunc();

委托是一個能夠指向方法的指針,而它的構造函數就是需要一個方法,接着我們來定義一個返回值為Boolean,能接收一個int類型參數的方法

//相當於方案1
public static Boolean Condition1(int i)
{
    //模擬復雜的操作 相當於return i%10==0;
    int x = i % 10;
    if (i % 10 == 0)
    {
        return true;
    }
    else {
        return false;
    }
}

定義好了方法我們再來實例化一個DelegateFunc類型的對象

//構造函數放入方法的話不需要帶(),帶()的話是調用
DelegateFunc func = new DelegateFunc(Condition1);

下面看一下下面這種聲明委托類型的方式

//同樣都是類型Object類型可以這樣寫
//因為String最終是繼承自Object,並且String可以默認轉換為Object
Object obj = "obj";
//而DelegateFunc也可以通過這種方式賦值,這說明Condition1可以默認轉換為委托類型
DelegateFunc func = Condition1;

實例化完成之后func變量就會指向Condition1方法,調用方式如下

//調用委托類型的對象和調用普通的方法是一樣的
func(10);

然后我們把剛才寫的GetNum方法修改為如下的樣子,參數為接收一個DelegateFunc類型的參數,也就是委托類型

public static List<int> GetNum(DelegateFunc func)
{
    List<int> lst = new List<int>();
    for (int i = 1; i < 1000; i++)
    {
        //調用傳過來的方法,根據調用者傳過來的方法拿到想要的數字
        if (func(i))
        {
            lst.Add(i);
        }
    }
    return lst;
}

在Main方法中調用GetNum方法

//聲明委托
DelegateFunc func = new DelegateFunc(Condition1);
//調用方法
List<int> lst = GetNum(func);
//也可以直接調用,因為都會默認轉換
//List<int> lst = GetNum(Condition1);
//輸出
foreach (int item in lst)
{
    Console.WriteLine(item);
}

 

輸出

如果我們有新的方案的話,只需要在新建一個方案,然后傳入方法中,比如我們還看剛才那個求1-1000以內8的倍數,我們只需要聲明一個新的方案

//聲明一個新的方案2
public static Boolean Condition2(int i) {
    //同樣模擬復雜的操作 相當於return i%8==0;
    int x = i % 8;
    if (i % 8 == 0)
    {
        return true;
    }
    else {
        return false;
    }
}

然后和剛才一樣,聲明一個委托就行,傳入GetNum就行。

不過我們看一下,雖然已經比較簡化代碼了,但是寫起來還是很麻煩,然后我們來看一下lambda表達式

3、lambda表達式

首先lambda表達式只是方法的一種寫法!lambda聲明的方法是匿名方法,它和委托並不是綁死的,這是兩個東西,但是lambda表達式和委托結合使用是非常常見的!

 看一下lambda表達式的語法,也就是函數的另一種寫法

//可以這樣寫
//DelegateFunc func = new DelegateFunc((i) =>
//{
//    return i % 8 == 0;
//});
//也可以這樣 不進行new DelegateFunc操作,因為會默認轉換
//如果有多句的話,這樣寫每一句通過分號隔開
DelegateFunc func = (i) => { return i % 8 == 0; };
//如果只有單句 不用寫return    默認reuturn   i%8==0 這一句計算出來的值
func = (i) => i % 8 == 0;
//如果只有一個參數   多個參數的話要(i,j,....)這樣寫
func = i => i % 8 == 0;

除此之外lambda也可以用來聲明方法,貌似只能寫一句,,,,

//無返回值
public static void HelloWord() => Console.WriteLine("Hello Word!");
//有返回值
public static String GetHelloWord() => "Hello Word!";

有了lambd我們再來調用GetNum,就會變得非常方便

//8的倍數
List<int> lst = GetNum((i) => i % 8 == 0);
//10的倍數
lst = GetNum(i => i % 10 == 0);
//20的倍數
lst = GetNum(i => i % 20 == 0);

4、Action和Func

Action和Func是微軟已經定義好的的兩種委托類型,區別是Action是沒有返回值的,而Func是需要返回值的

Action使用方法

//無參數
Action action1 = () => Console.WriteLine("action");
//有參數的話調用Action<T>
Action<int> action2 = (i) => Console.WriteLine(i);
//多個參數就在生命的時候<T,T,T>
Action<int,string> action3 = (i, str) => Console.WriteLine(i+"\t"+str);
//調用
action1();
action2(10);
action3(10,"s");

運行結果:

Func使用方法

//Func是沒有Func類型的,只有Func<T>類型
Func<string> func1 = () => "func";
//如果需要參數 Func<T,T,T>  
//最后一個T類型為返回值類型,前面的全都為參數的類型!!!
Func<string, int> func2 = (i) => int.Parse(i);
//如果有多個參數     最后一個T類型為返回值類型,前面的全都為參數的類型!!!
Func<int, string, int> func3 = (i, str) => int.Parse(i + str);

//調用
Console.WriteLine(func1());
Console.WriteLine(func2("123"));
Console.WriteLine(func3(1,"23"));

運行結果

 


免責聲明!

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



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