程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 10.C#匿名函數的變量捕獲(五章5.5),

10.C#匿名函數的變量捕獲(五章5.5),

編輯:C#入門知識

10.C#匿名函數的變量捕獲(五章5.5),


  首先感謝園友的指定,後續的文章一定會多碼多想,出來的文章才有說服力。那今天接上篇我們來聊一聊匿名函數,對於匿名函數,我們知道使用delegate關鍵字,那我們來需要知道匿名函數在變量是的處理方式,先說兩個術語,外部變量和捕獲的外部變量,可以看出"捕獲的外部變量=外部變量+捕獲了",這個捕獲顧名思義就是在匿名函數中使用了這個變量。

  外部變量:指在一個包含匿名方法的作用域內的變量或者參數,在類的實例成員內部的匿名方法,this也是認為是一個外部變量。

  捕獲的外部變量:它是指在匿名方法中使用的外部變量。

  代碼如下

 1 static void Main(string[] args)
 2 {
 3     //x和y稱為外部變量
 4     int x = 0, y = 1;
 5     //在匿名方法中使用到了x,則x稱為捕獲的外部變量
 6     Action<int> ac = delegate (int n) { Console.WriteLine(x); };
 7 
 8     //小結:x、y和匿名方法都在Main函數的作用域內,也可以擴展到類的作用域及命名空間的作用域
 9 
10     Console.ReadKey();
11 }

  再來說下匿名方法捕獲變量的行為,可以看到在匿名方法中我們訪問到了局部變量x,請注意,並不是僅僅訪問到了x的值,而是在匿名類型中使用一個類型實例引用到了變量x,對於x的改變,因為是引用,所以總能使用這個類型實例訪問到,如

1 long x1 = 11, y1 = 12;
2 Action<long> ac1 = delegate (long l) { Console.WriteLine(x1); };
3 ac1(1L); //打印11
4 x1 = y1;
5 ac1(1L);  //打印12

  參數long l這裡沒有使用到,不過這裡的參數不是上面所說的外部變量,因為它確實是匿名方法的參數

1 static void Debug(int x) {
2     Action<int> a = delegate (int y) { Console.WriteLine(x); };
3 }

  上面的x就是術語中說的外部變量,分清定義就應該沒問題了吧。

  關於變量的生存周期,可以就只在一個作用域內,當代碼執行完這個作用域,該作用域內的變量也會被銷毀,但使用匿名方法可以延長變量的生存周期。

 1 static void Main(string[] args)
 2 {
 3     GetLen gl = GetMethod();
 4     gl("s"); //打印00s
 5     gl("s"); //打印0000s
 6 
 7     Console.ReadKey();
 8 }
 9 
10 public delegate int GetLen(string s);
11 static GetLen GetMethod()
12 {
13     string temp = "0";
14     return delegate (string s) {
15         temp = String.Concat(temp, temp);
16         s = String.Concat(temp, s);
17         Console.WriteLine(s);
18         return s.Length;
19     };
20 }

  看出使用GetMethod返回一個委托,這裡使用匿名函數(因為匿名函數就是對應簽名的委托),在正常理解下temp在GetMethod作用域內,當離開作用域外,這個變量會銷毀,但說過匿名函數會使用一個類型實例引用這個變量,則這個變量不會銷毀,只有當匿名函數銷毀(也就是委托)才會跟著銷毀,從而延長了變量的作用域,而且對於temp變量的操作也會直接反應在實例引用的變量上,如第一次調用gl("s"),temp="00",第二次調用時,temp="0000"。

   最後說下有點繞的東西,就是變量的實例化在匿名函數中的訪問規則,不過個人感覺這個還真是不很繞,還算是比較好理解的。看下代碼。

 1 GetLen[] a = { };
 2 int xx = 0;
 3 for (int i = 0; i < 3; i++)
 4 {
 5     int xxx = i;
 6     a[i] = delegate (string s) {
 7         xx++;
 8         xxx++;
 9         return xx + xxx;
10     };
11 }

  a是一個委托數組,對於數組中每一個委托都共享一個xx實例引用,而每一個委托都各自擁有一個xxx實例引用(xxx對應不同的委托是不同的),這是因為在循環中,每一次的循環都實例化了xxx,則對於各個委托都有一個全新的xxx實例引用,而xx則是在循環之外實例化的,則每個委托共享一個實例引用。當然在實際的使用過程中,不可能那麼簡單,那麼要我們開動大腦,好好區別哪一個共享的,哪一個是獨自引用的。

  請斧正。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved