1. 程式人生 > 其它 >匿名方法和Lambda表示式

匿名方法和Lambda表示式

匿名方法和Lambda表示式

1、匿名方法

在C#2.0版本中引入了匿名方法,匿名方法與具名方法(即普通的方法)相對

簡單示例:

delegate void MyDelegate(int x); //宣告一個委託型別

void Main()
{
	MyDelegate del = delegate(int x)
	{
		Console.WriteLine($"匿名方法輸出值:{x}");	
	};
	
	del(20);
}

使用場景

  1. 給初始化委託變數
  2. 給組合委託賦值
  3. 給委託增加方法

語法

匿名方法必須與關聯的委託保持格式一致,也就是返回值和引數需要相同,注意語句塊後面是有分號的,不要漏掉

delegate(引數列表) {語句塊};

返回值

匿名方法不會顯示地宣告返回值,但是返回值要和對應的委託保持一致。如果委託沒有返回值,即為void時,匿名方法則不能有返回值;如果委託有返回值,則匿名函式需要在語句塊中返回對應型別的值。

delegate int MyDelegate(int x); //宣告一個委託型別

void Main()
{
	MyDelegate del = delegate(int x)
	{
		Console.WriteLine($"匿名方法輸出值:{x}");	
		return (x + 10);
	};    
}

引數列表

引數列表要和宣告的委託保持一致,也就是引數的個數、型別及位置。

當委託沒有out引數或匿名方法沒有輸入引數時,則可以省略匿名方法的引數列表。當匿名方法不需要輸入引數時,這種情況下引數列表可以和委託不一致了,但同時在呼叫委託時,傳入的引數也不會起到作用。

delegate int MyDelegate(int x); //宣告一個委託型別

void Main()
{
	MyDelegate del = delegate
	{
		Console.WriteLine($"匿名方法不需要使用輸入引數");	
		return 10;
	};
	
	del(20);
}    

如果在委託型別的宣告中,引數列表使用了params引數,則匿名方法的引數列表會忽略params關鍵字的作用。

外部變數的捕獲

在匿名方法中使用方法塊外部的變數很簡單,可以直接使用

delegate int MyDelegate(int x); //宣告一個委託型別

void Main()
{
	int val = 20;
	MyDelegate del = delegate
	{
        //捕獲匿名方法外部的val變數
		Console.WriteLine($"匿名方法輸出:{val+10}");	
		return 10;
	};
	
	del(20);
}    

輸出:

匿名方法輸出:30

捕獲變數的生命週期會在委託被呼叫時得到擴充套件

MyDelegate del;
	
{
    int val = 20; //val變數的作用域和生命週期在此程式碼塊中

    del = delegate
    {
        Console.WriteLine($"匿名方法輸出:{val + 10}");
        return 10;
    };
}

del(20); //委託呼叫時,由於匿名方法捕獲了val變數,val變數的生命週期在此得到延續

2、Lambda表示式

在C#3.0中引入Lambda,簡化了匿名方法,用來替代匿名方法。lambda表示式相比匿名方法,不需要使用delegate關鍵字,並且有更精簡的寫法,易於理解也提高了效率。

使用場景

和匿名方法一樣,作為委託delegate的初始化方法或給委託增加方法

還可以用在屬性的get、set中

語法格式

Lambda運算子=>,讀作 goes to

引數列表 => 方法塊

示例:

delegate void MyDelegate(int x); //宣告一個委託型別

void Main()
{
	MyDelegate del;
	del = delegate (int x) { Console.WriteLine($"匿名方法輸出:{x}"); }; //匿名方法
	del = (int x) => { Console.WriteLine($"Lambda表示式輸出:{x}"); }; //lambda表示式
	del(20);
}

帶返回值

delegate int MyDelegate1(int x); //宣告一個委託型別

void Main()
{
	MyDelegate1 del1;
	del1 = x => 
	{
		Console.WriteLine($"Lambda表示式輸出:{x}");
		return 10;
	};
	
	del1(100);
}

引數列表

  1. 引數列表一般來說格式要和委託型別保持一致
  2. 沒有引數時,必須要用空的()來表示
  3. 只有一個引數時,可以省略()
  4. Lambda表示式中引數型別可以省略,除非委託引數中有ref和out修飾的引數,則不可省略

引數列表帶有型別稱為顯示型別,沒有型別稱為隱式型別

delegate void MyDelegate(int x); //宣告一個委託型別

void Main()
{
	MyDelegate del;
	del = (int x) => { Console.WriteLine($"Lambda表示式輸出:{x}"); };
	del = (x) => { Console.WriteLine($"Lambda表示式輸出:{x}"); }; //省略型別
	del = x => { Console.WriteLine($"Lambda表示式輸出:{x}"); }; //省略()
	del = x => Console.WriteLine($"Lambda表示式輸出:{x}"); //只有一條語句,也可以放return的表示式

	del(20);
}

多個引數

delegate int MyDelegate2(int x, int y, int z); //宣告一個委託型別

void Main()
{
	MyDelegate2 del2, del3, del4;
	del2 = (int x, int y, int z) =>
	{
		Console.WriteLine($"x = {x},  y = {y},  z = {z}");
		return 20;
	};

	del3 = (x, y, z) => x + y + z; //省略引數型別,一個語句作為return表示式 
	//del4 = x, y, z => x + y + z; //多個引數時無法省略()
	
	del2(3, 5, 7);
	Console.WriteLine(del3(3, 5, 7));
}

輸出

x = 3, y = 5, z = 7
15