C#中Delegate,Action,Func,Predicate的使用與區別

Unity C#中Delegate,Action,Func,Predicate的使用與區別

目的:C# 內置了幾個常用委託 Action,Action,Func,Predicate,一般我們要用到委託的時候,儘量不要自己再定義一個委託了,就用系統內置的這幾個已經能夠滿足大部分需求,且讓代碼符合規範。

C# 4.0 之後,Lamda ,Linq 表達式等許多新的程序寫法層次不窮。與之相關的 Delegate,Action,Func,Predicate 的使用和區別讓人迷惑。

委託 Delegate

匿名函數是針對 delegate 使用的。

泛型

private T GetData <T> where T:Object,new()
{
 T t=new T;
return t;
}

<> 表示當前函數爲泛型。

public delegate void Action<in T>(T obj);

之前必須將 Delegate 聲明到類外面,作爲全局的才能在其他地方看見並使用。

Action 無返回值

Action 沒有參數也沒有返回值。

Action < T > 無返回值

Action,Func 改變了這個狀態,說白了就是系統定義好的 Delegate ,他有很多重載的方法,便於各種應用情況下的調用。因爲在系統 System 命名空間下,因此全局可見。

Action: 封裝了一個方法,該方法只有一個參數並沒有返回值。T 是可接受的任何類型。

Action 多個重載就是 <> 中可以添加多個類型。

在實際應用中,Action 要比原來定義 Delegate 靈活,方便很多。

Func<in T,out Tresult> 返回值是定義的類型

封裝一個具有一個參數並返回 Tresult 參數指定的類型值的方法。

Func 和 Action 區別很明顯,也很直接。

二者都是委託,但 Func 能返回函數執行結果,而 Action 返回類型是 void,這個區別很明顯,也很容易確定該使用哪個。

Predicate < T > 返回值總是 bool 值

也是一種委託,表示定義一組條件並確定指定對象是否符合這些條件的方法。此方法常在集合的查找中被用到。

參考:https://www.jianshu.com/p/619a930d75b3

總結:

  • 如果要委託的方法沒有參數也沒有返回值就想到Action
  • 有參數但沒有返回值就想到Action
  • 無參數有返回值、有參數且有返回值就想到Func
  • 有bool類型的返回值,多用在比較器的方法,要委託這個方法就想到用Predicate
  • 參考 https://www.cnblogs.com/maitian-lf/p/3671782.html

參考腳本,幫助理解:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/// <summary>
///  system 系統中聲明瞭一個全局的委託泛型,
///  <T> T 表示你可以定義這個泛型爲任意類型的委託,
///  而在腳本中聲明 Action<string> myAction 表示,定義這個泛型委託具體爲 string 類型委託
///  腳本中的變量就是這個 string 類型委託的具體變量
/// </summary>
public class TestAction : MonoBehaviour
{

    #region  delegate 基礎
    public delegate void ShowDel(int a);//定義委託類
    ShowDel showDel;//委託類對象
    void Start()
    {
        //函數的內存地址給了showDel
        showDel = new ShowDel(ShowMyData);//初始化委託指向函數
        showDel(1);//直接調用委託,找到內存地址調用函數


        //底層是一個數組,調用的時候遍歷一下
        showDel += ShowMyData2;//初始化委託指向函數
        showDel += ShowMyData1;
        //showDel-=ShowMyData1; 取消委託
        showDel(1);//三個函數都會調用
    }
    void ShowMyData(int a)
    {
        Debug.Log(a);
    }
    void ShowMyData1(int a)
    {
        Debug.Log(a);
    }
    void ShowMyData2(int a)
    {
        Debug.Log(a);
    }


    #endregion

    #region Action
    //Action 封裝的方法沒有參數也沒有返回值
    public void Alert()
    {
        Debug.Log("Action test");
    }

    void StartAction()
    {
        Action ac = new Action(Alert);
        Action t = () => { Debug.Log("Action test"); };//語句簡短也可以使用 Lambda 表達式
        ac();//調用 委託
        t();
    }
    
    #endregion 

    #region Action<T> 
    public string myName;
    Action<string> myAction;
    //
    public TestAction()
    {
        // 三種 Action 使用方法   調用委託  注意第一種方法和第三種只是 delegate,=> 的區別
        myAction = delegate (string curName) { myName = curName; };//匿名委託
        myAction = new Action<string>(SetAction);//指定一個實際方法
        myAction = curname => { myName = curname; };//使用 Lamda 表達式。     //匿名函數就是沒有函數體,直接 參數 => 具體方法語句
    }
    void SetAction(string name)
    {
        myName = name;
    }
    #endregion

    #region Func<in T,T Tresult>
    public string Name;
    Func<string, string> myFunc;
    
    public void UseFunc()
    {
        //三種使用 Func 的方式
        myFunc = delegate (string curName) { return curName.ToUpper(); };
        myFunc = new Func<string, string>(SetFunc);
        myFunc = mName => { return mName.ToUpper(); };//匿名函數的優點,就是根據使用當前函數出現的變量,代碼更簡潔,但可能有些不易讀
    }

    string SetFunc(string name)
    {
        return name.ToUpper();
    }

   /// <summary>
   /// 注意這個用法
   /// </summary>
   /// <param name="curName"></param>
    public void StartFunc(string curName)
    {
        Name = myFunc(curName);
    }
    #endregion

    #region Predicate<T>
    Predicate<int> myPredicate;
    int[] myNum = new int[8] { 12, 33, 89, 21, 15, 29, 40, 52 };
    public int[] myResult;

    public void TestPredicate()
    {
        myPredicate = delegate (int curNum) 
        {
            if (curNum % 2 == 0)
                return true;
            else
                return false;
        };
    }
    /// <summary>
    /// 第二個參數就是 Predicate,在具體的執行中,每一個數組的元素都會執行特定的方法,如果滿足要求返回 true,
    /// 並會被存在在結果集中,不符合的被踢出,最終返回的集合,即是判斷後想要的集合。此方法感覺像是迭代中的 yield 。也可以用上面三種寫法
    /// </summary>
    public void StartPredicate()
    {
        myResult = Array.FindAll(myNum, myPredicate);
        
    }
    #endregion
}


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