Lambda 運算式筆記

來源:互聯網
上載者:User
     MSDN 定義:"Lambda 運算式" 是一個匿名函數,它可以包含運算式和語句, 並且可用於建立委託或運算式樹狀架構類型.
匿名方法是在2.0中引入,在之後的3.0 及 更高版本中, Lambda運算式取代了匿名方法,作為編寫內聯代碼的首選方式. 因為在之前項目中一直沒用,也沒去瞭解, 所以現在整理一下, 趕緊補上這一課.
首先, 回顧一下匿名函數: 
要將代碼塊傳遞為委託參數,那麼唯一的方法就是建立匿名函數, Example
delegate void Fun(string str);
Fun f = delegate(string str){
    Console.WriteLine(str);
};
f("hello world");
通過使用匿名方法, 因為不必建立單獨的方法, 所以減少了執行個體化委託所需的系統開銷.
線程也是一個很好的例子:
 System.Threading.Thread thd = new System.Threading.Thread
                (
                    delegate()
                    {
                        Console.WriteLine("first");                        
                    }
                );
            thd.Start();
OK 現在回到"Lambda 運算式"
所有Lambda 運算式都使用 =>, 該運算子讀為"goes to", 運算子左邊是輸入參數(如果有), 右邊包含運算式或者代碼語句塊. x=>x * x 讀作:"x goes to x times x"
=>運算子與賦值(=)有相同的優先順序,並且是右結合運算子.
1、Lambda 運算式
運算式在右邊的 Lambda運算式稱為"Lambda 運算式' (input parameters)=> expression
當只有一個參數時,左邊輸入參數括弧才是可選的, 兩個或更多輸入參數, 則必須有括弧, 參數用逗號分隔 
(x,y)=> x==y
有時,編譯器無法推斷輸入類型, 你可以顯式指定參數類型:
(int x, string s) => s.Length > x
使用空括弧指定零個輸入參數:
() => SomeMethod()
2、Lambda 語句
Lambda 語句與 Lambda 運算式類似, 把執行語句塊放到大括弧中 (input 
parameters) => {statement;}
Lambda 
語句塊可以包含任意數量語句, 但是實際項目中盡量以少為宜, 這樣讀起來比較清晰,一般也就三個語句.
delegate void Fun(string str1,string str2);
 Fun f = (n, m) => { Console.WriteLine(n + m + "World"); };
            f("Hello", "Our");
3、帶有標準查詢運算子的Lambda
許多標準查詢運算子都具有輸入參數, 
其類型是泛型委派Func<T,TResult>系列之一. Lambda 運算式的基礎類型是泛型 Func 委託之一.
Func<T,TResult>委託:封裝一個具有一個參數並返回 TResult 參數指定的類型值的方法。
public delegate TResult Func<in T, out TResult>(
    T arg
)
下面就執行個體化一個Func<int,bool> 委託, int 是輸入參數,bool 是傳回值.Example
Func<int, bool> myFun = x => x == 7; or Func<int, bool> myFun = (int x) => x == 7;  
            bool b = myFun(5); // false
下面顯示一個標準查詢運算子:
 int[] numbers = { 3, 4, 5, 6, 7 };
            int SumNumbers = numbers.Count(n => n % 2 == 1);  //3
這裡Count方法
public static int Count<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
)
其中source 包含測試和計數的元素的序列. predicate 測試每個元素是否滿足條件的函數
4、Lambda 中的類型推斷
在編寫Lambda時,通常不必為輸入參數指定類型, 編譯器可以根據Lambda 主體、基礎委託類型和C#語言規範描述的其他因素推斷類型.
而大多數標準查詢運算子,第一個輸入是源序列中的元素類型.
customers.Where(c => c.City == "ShangHai"); //這裡的輸入參數 c 就被推斷為customers 對象 
Lambda的一般規則:
·Lambda包含的參數數量必須與委託類型包含的參數數量一致 
·Lambda中每個輸入參數必須能隱式轉換成其對應的委託參數 
·Lambda傳回值必須能夠隱式轉換成委託的傳回型別? 
5、Lambda運算式中的變數範圍
先看一段代碼
delegate bool del();
    delegate bool del2(int i);
    class Program
    {
        del del;
        del2 del2;      
        static void Main(string[] args)
        {         
            Program test = new Program();
            test.TestMethod(5);           
            bool result = test.del2(10);
            Console.WriteLine(result);
            Console.Read();
        }
        public void TestMethod(int input)
        {
            int j = 0;          
            del = () => { j = 10; return j > input; };          
            del2 = (x) => { return x == j; };          
            Console.WriteLine("j = {0}", j);           
            bool boolResult = del();
            Console.WriteLine("j = {0}.b = {1}", j, boolResult); 
        }        
    }
看看輸出結果
MSDN解釋:Lambda 可以引用“外部變數”,這些變數位於在其中定義 Lambda 的封閉方法或類型的範圍內。 將會儲存通過這種方法捕獲的變數以供在 Lambda 運算式中使用,即使變數將以其他方式超出範圍或被作為記憶體回收。 必須明確地分配外部變數,然後才能在 Lambda 運算式中使用該變數。
看起來比較難理解一點, 具體針對下面規則做一些解釋,有理解錯誤的地方還請各位大俠指出 J
? 
1)捕獲的變數將不會被作為記憶體回收,直至引用變數的委託超出範圍為止。
      Lambda所使用的變數,在委託的生命週期內不會被記憶體回收. 要讓委託承載的方法數超出範圍估計很難達到, 
     這個具體委託能承載多少個方法,我也想知道, 我試了載入100W個方法,也沒出現問題, 這個應該和記憶體有關, 只要你機器有足夠的記憶體.
2)在外部方法中看不到 Lambda 運算式內引入的變數。
delegate bool D();
 D del;
  for (int a = 0; a < 4; a++)
            {
                del += () => { int t = 0; return true; };
                Console.WriteLine("t={0}", t);   //這裡無法訪問Lambda中定義的變數t
            }
3)Lambda 運算式無法從封閉方法中直接捕獲 ref 或 out 參數。 
    如果委託中有ref或out參數,則Lambda必須有參數類型(即顯示類型)     
delegate bool D2(int i,ref string str);
D2 del2;
for (int a = 0; a < 4; a++)
 {
   del2 += (int x, ref string c) => 
   { c = c + "j"; Console.WriteLine(x + c); return true; };//這裡必須顯示參數類型 x, c}
string s="sadf"; 
del2(5,ref s); 
Console.WriteLine(s);
 4)Lambda 運算式中的返回語句不會導致封閉方法返回。
    Lambda運算式中return 只是跳出Lambda, 然後繼續執行方法中Lambda下面的語句, 不會跳出當前所在的方法.
5)Lambda 運算式不能包含其目標位於所包含匿名函數主體外部或內部的 goto 語句、break 語句或 continue 語句。   
del += () => { int t = 0; break; return true; };
//這裡會出現如下語法錯誤 Control cannot leave the body of an anonymous method or lambda expression

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.