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
}