C#Lambda表示式
阿新 • • 發佈:2019-01-05
需求
有時候我們需要傳遞一個很方法的引用,我們很確定這個方法僅僅會呼叫這一次,單獨為它建立一個方法感覺有些浪費,但是又必須用到這個方法。又或者臨時需要一個方法,但是思考半天想不出該給這個方法取什麼名字(有過這個經歷的同學握個爪)。這個時候Lambda就派上用場了。
是什麼
Lambda 表示式是一種可用於建立委託或表示式目錄樹型別的匿名函式。通過使用 lambda 表示式,可以寫入可作為引數傳遞或作為函式呼叫值返回的本地函式。Lambda 表示式對於編寫 LINQ 查詢表示式特別有用。
若要建立 Lambda 表示式,需要在 Lambda 運算子 => 左側指定輸入引數(如果有),然後在另一側輸入表示式或語句塊。例如,lambda 表示式 x => x * x 指定名為 x 的引數並返回 x 的平方值,你可以將此表示式分配給委託型別。
說明
- => 運算子具有與賦值運算子 (=) 相同的優先順序並且是右結合運算(參見“運算子”文章的“結合性”部分)。
- Lambda 在基於方法的 LINQ 查詢中用作標準查詢運算子方法(如 Where)的引數。
- 使用基於方法的語法在 Enumerable 類中呼叫 Where 方法時(如在 LINQ to Objects 和
LINQ to XML 中一樣),引數是委託型別System.Func<T, TResult>
。使用 Lambda表示式建立該委託最為方便。例如,當你在 System.Linq.Queryable 類中呼叫相同的方法時(如在LINQ to SQL中一樣),引數型別為 System.Linq.Expressions.Expression,其中 Func是最多具有十六個輸入引數的任何一個Func委託。同樣,Lambda 表示式只是一種非常簡潔的構造該表示式目錄樹的方式。儘管事實上通過Lambda建立的物件具有不同的型別,但Lambda 使得 Where呼叫看起來類似。
注意
- 如果Lambda表示式要獲取引數,就在=>操作符左側的圓括號內指定。可省略引數型別,C#編譯器能根據Lambda表示式的上下文進行推斷。如果希望Lambda表示式永久(而不是區域性)更改引數值,可以用“傳引用”的方式傳遞引數(使用ref關鍵字),但不推薦這樣做。
- Lambda表示式可以返回值,但返回型別必須與即將新增這個Lambda表示式的委託的型別匹配。
- Lambda表示式的主體可以是簡單表示式,也可以是C#程式碼塊(程式碼塊可包含多個語句、方法呼叫、變數定義等等)。
- Lambda表示式方法中定義的變數會在方法結束時離開作用域。
- Lambda表示式可訪問和修改Lambda表示式外部的所有變數,只要那些變數在Lambda表示式定義時,和Lambda表示式處在相同的作用域中。
怎麼用
準備工作
委託定義
public delegate void LambdaHandle0();
public delegate void LambdaHandle0s();
public delegate void LambdaHandle1(int x);
public delegate void LambdaHandle2(int x,int y);
public delegate void LambdaHandle3(ref int x,int y);
事件定義
public class LambdaEvent{
//無參事件1
public event LambdaHandle0 thisEvent0;
//無參事件2
public event LambdaHandle0s thisEvent0s;
//一個整形引數事件
public event LambdaHandle1 thisEvent1;
//兩個整形引數事件
public event LambdaHandle2 thisEvent2;
//兩個整形引數事件,第一個引數為引用傳遞
public event LambdaHandle3 thisEvent3;
public void callEvent0(){
if(thisEvent0!=null)
thisEvent0 ();
}
public void callEvent0s(){
if(thisEvent0s!=null)
thisEvent0s ();
}
public void callEvent1(int x){
if(thisEvent1!=null)
thisEvent1 (x);
}
public void callEvent2(int x,int y){
if(thisEvent2!=null)
thisEvent2 (x,y);
}
public void callEvent3(ref int x,int y){
if(thisEvent3!=null)
thisEvent3 (ref x,y);
}
}
用於事件的方法定義
private void myFunction(string str){
Debug.Log ("str="+str);
}
具體用法
例項化事件
LambdaEvent myEvent=new LambdaEvent();
###無參表示式
myStr="myStr";
myEvent.thisEvent0+=()=>myFunction(myStr);
myEvent.callEvent0 ();
myEvent.thisEvent0s+=()=>Debug.Log("Lambda");
myEvent.callEvent0s ();
一個引數的表示式
int a=10;
//引數型別省略,自動根據上下文判斷
myEvent.thisEvent1 +=x => Debug.Log("x*x="+ x * x);
myEvent.callEvent1 (a);
多個引數的表示式
int a=10,b=10;
myEvent.thisEvent2+=(x,y)=>{x=x*y;Debug.Log("x="+x);};
myEvent.callEvent2 (a,b);
//普通傳值,引數值不變
Debug.Log ("a="+a);
傳遞引用引數的表示式
//第一個引數為引用。注意此時必須指明引數型別
myEvent.thisEvent3+=(ref int x,int y)=>{x=x*y;Debug.Log("x="+x);};
myEvent.callEvent3 (ref a,b);
Debug.Log ("ref a="+a);
帶有標準查詢運算子的Lambda
//用於泛型委託Func
Func<int, bool> myFunc = x => x == 5;
Debug.Log("myFunc(5)="+myFunc(5));
//用於Linq查詢
int[] number = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Debug.Log ("Count="+number.Count(n=>n%2==1));
List<int> numList = number.TakeWhile (n => n < 6).ToList ();
if (numList != null)
foreach (int i in numList)
Debug.Log (i);
完整指令碼
using UnityEngine;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public delegate void LambdaHandle0();
public delegate void LambdaHandle0s();
public delegate void LambdaHandle1(int x);
public delegate void LambdaHandle2(int x,int y);
public delegate void LambdaHandle3(ref int x,int y);
public class MyLambda : MonoBehaviour {
void Start () {
LambdaEvent myEvent=new LambdaEvent();
string myStr="myStr";
myEvent.thisEvent0+=()=>myFunction(myStr);
myEvent.callEvent0 ();
myEvent.thisEvent0s+=()=>Debug.Log("Lambda");
myEvent.callEvent0s ();
int a=10,b=10;
//引數型別省略,自動根據上下文判斷
myEvent.thisEvent1 +=x => Debug.Log("x*x="+ x * x);
myEvent.callEvent1 (a);
myEvent.thisEvent2+=(x,y)=>{x=x*y;Debug.Log("x="+x);};
myEvent.callEvent2 (a,b);
//普通傳值,引數值不變
Debug.Log ("a="+a);
//第一個引數為引用。注意此時必須指明引數型別
myEvent.thisEvent3+=(ref int x,int y)=>{x=x*y;Debug.Log("x="+x);};
myEvent.callEvent3 (ref a,b);
Debug.Log ("ref a="+a);
//用於泛型委託Func
Func<int, bool> myFunc = x => x == 5;
Debug.Log("myFunc(5)="+myFunc(5));
//用於Linq查詢
int[] number = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Debug.Log ("Count="+number.Count(n=>n%2==1));
List<int> numList = number.TakeWhile (n => n < 6).ToList ();
if (numList != null)
foreach (int i in numList)
Debug.Log (i);
}
private void myFunction(string str){
Debug.Log ("str="+str);
}
}
public class LambdaEvent{
//無參事件1
public event LambdaHandle0 thisEvent0;
//無參事件2
public event LambdaHandle0s thisEvent0s;
//一個整形引數事件
public event LambdaHandle1 thisEvent1;
//兩個整形引數事件
public event LambdaHandle2 thisEvent2;
//兩個整形引數事件,第一個引數為引用傳遞
public event LambdaHandle3 thisEvent3;
public void callEvent0(){
if(thisEvent0!=null)
thisEvent0 ();
}
public void callEvent0s(){
if(thisEvent0s!=null)
thisEvent0s ();
}
public void callEvent1(int x){
if(thisEvent1!=null)
thisEvent1 (x);
}
public void callEvent2(int x,int y){
if(thisEvent2!=null)
thisEvent2 (x,y);
}
public void callEvent3(ref int x,int y){
if(thisEvent3!=null)
thisEvent3 (ref x,y);
}
}