程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Lambda表達式的本質是匿名函數,lambda表達式

Lambda表達式的本質是匿名函數,lambda表達式

編輯:C#入門知識

Lambda表達式的本質是匿名函數,lambda表達式


1.委托的簡介:

委托可以簡單的理解為方法的列表,添加的方法的參數類型,個數,順序必須和委托一致,

                           也就是說委托起到了托管方法的作用,並且約束了要調用的方法.

1         //1聲明委托  
2         public delegate void NoReturnNoPara();
3         public delegate void NoReturnWithPara(string name, int id);
4         public delegate int WithReturnNoPara();
5         public delegate string WithReturnWithPara(string name);

基礎代碼:

1 private void ShowPerson(string name, int id) 2 { 3 Console.WriteLine("this is id={0} name={1}", id, name); 4 } ShowPerson 1 public class Student 2 { 3 public int Id { get; set; } 4 public int ClassId { get; set; } 5 public string Name { get; set; } 6 public int Age { get; set; } 7 8 public void Study() 9 { 10 Console.WriteLine("正在學習高級班"); 11 } 12 } 13 14 /// <summary> 15 /// 班級 16 /// </summary> 17 public class Class 18 { 19 public int Id { get; set; } 20 public string Name { get; set; } 21 } Student 1 { 2 Student student = new Student() 3 { 4 Id = 1, 5 ClassId = 11, 6 Name = "Courage-dhj" 7 }; 8 student.Study(); 9 10 var people = new //匿名類 11 { 12 Id = 1, 13 ClassId = 11, 14 Name = "Courage-dhj" 15 }; 16 Console.WriteLine("{0} {1} {2}", people.Id, people.Name, people.ClassId); 17 } 匿名類
1             {
2                 NoReturnWithPara method = new NoReturnWithPara(ShowPerson);//2 實例化委托
3                 method.Invoke("盜墓者", 468);//3 委托調用
4                 ShowPerson("盜墓者", 468);//方法的普通調用
5             }

 

2.匿名方法:      用delegate代替了方法名而已(修飾符和返回類型這裡看作方法名)

1            {
2                 NoReturnWithPara method = new NoReturnWithPara(
3                     delegate(string name, int id)
4                     {
5                         Console.WriteLine("this is id={0} name={1}", id, name);
6                     });//匿名方法
7                 method.Invoke("盜墓者", 468);
8             }

 

3.Lambda表達式  

1            {
2                 NoReturnWithPara method = new NoReturnWithPara(
3                     (string name, int id) =>
4                     {
5                         Console.WriteLine("this is id={0} name={1}", id, name);
6                     });//lambda表達式  把delegate換成箭頭
7                 method.Invoke("盜墓者", 468);
8                 //lambda表達式的本質就是一個匿名方法,,也就是一個方法
9             }

 

因為委托對方法有約束作用,所以,方法的參數類型可以省略

1          {
2                 NoReturnWithPara method = new NoReturnWithPara(
3                                    (name, id) =>//lambda表達式方法主體只有一行,可以去掉大括號和分號
4                                        Console.WriteLine("this is id={0} name={1}", id, name)
5                                    );
6                 method.Invoke("盜墓者", 468);
7             }

其他的形式:

1           {
2                 NoReturnWithPara method = new NoReturnWithPara(
3                                    (name, id) =>//lambda表達式方法主體只有一行,可以去掉大括號和分號
4                                        Console.WriteLine("this is id={0} name={1}", id, name)
5                                    );
6                 method.Invoke("盜墓者", 468);
7             }
            {
                //new一個委托的時候,可以簡寫
                NoReturnWithPara method = (name, id) => Console.WriteLine("this is id={0} name={1}", id, name);//常用的形式
                method.Invoke("盜墓者", 468);
            }

 

4.  Action 和  Func----這是系統自帶的委托,方便我們使用.

4.1-Action-無返回值的委托---看下面的in也看的出來啦!

先查看系統代碼的說明:

 


1 namespace System
2 {
3     // 摘要: 
4     //     封裝一個方法,該方法不具有參數並且不返回值。
5     [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
6     public delegate void Action();
7 }

Action(一個參數)

 1 namespace System
 2 {
 3     // 摘要: 
 4     //     封裝一個方法,該方法只有一個參數並且不返回值。
 5     //
 6     // 參數: 
 7     //   obj:
 8     //     此委托封裝的方法的參數。
 9     //
10     // 類型參數: 
11     //   T:
12     //     此委托封裝的方法的參數類型。
13     public delegate void Action<in T>(T obj);
14 }

Action(in T)

 

1 1 namespace System 2 2 { 3 3 // 摘要: 4 4 // 封裝一個方法,該方法具有 16 個參數並且不返回值。 5 5 // 6 6 // 參數: 7 7 // arg1: 8 8 // 此委托封裝的方法的第一個參數。 9 9 // 10 10 // arg2: 11 11 // 此委托封裝的方法的第二個參數。 12 12 // 13 13 // arg3: 14 14 // 此委托封裝的方法的第三個參數。 15 15 // 16 16 // arg4: 17 17 // 此委托封裝的方法的第四個參數。 18 18 // 19 19 // arg5: 20 20 // 此委托封裝的方法的第五個參數。 21 21 // 22 22 // arg6: 23 23 // 此委托封裝的方法的第六個參數。 24 24 // 25 25 // arg7: 26 26 // 此委托封裝的方法的第七個參數。 27 27 // 28 28 // arg8: 29 29 // 此委托封裝的方法的第八個參數。 30 30 // 31 31 // arg9: 32 32 // 此委托封裝的方法的第九個參數。 33 33 // 34 34 // arg10: 35 35 // 此委托封裝的方法的第十個參數。 36 36 // 37 37 // arg11: 38 38 // 此委托封裝的方法的第十一個參數。 39 39 // 40 40 // arg12: 41 41 // 此委托封裝的方法的第十二個參數。 42 42 // 43 43 // arg13: 44 44 // 此委托封裝的方法的第十三個參數。 45 45 // 46 46 // arg14: 47 47 // 此委托封裝的方法的第十四個參數。 48 48 // 49 49 // arg15: 50 50 // 此委托封裝的方法的第十五個參數。 51 51 // 52 52 // arg16: 53 53 // 此委托封裝的方法的第十六個參數。 54 54 // 55 55 // 類型參數: 56 56 // T1: 57 57 // 此委托封裝的方法的第一個參數類型。 58 58 // 59 59 // T2: 60 60 // 此委托封裝的方法的第二個參數類型。 61 61 // 62 62 // T3: 63 63 // 此委托封裝的方法的第三個參數類型。 64 64 // 65 65 // T4: 66 66 // 此委托封裝的方法的第四個參數類型。 67 67 // 68 68 // T5: 69 69 // 此委托封裝的方法的第五個參數的類型。 70 70 // 71 71 // T6: 72 72 // 此委托封裝的方法的第六個參數的類型。 73 73 // 74 74 // T7: 75 75 // 此委托封裝的方法的第七個參數的類型。 76 76 // 77 77 // T8: 78 78 // 此委托封裝的方法的第八個參數的類型。 79 79 // 80 80 // T9: 81 81 // 此委托封裝的方法的第九個參數的類型。 82 82 // 83 83 // T10: 84 84 // 此委托封裝的方法的第十個參數的類型。 85 85 // 86 86 // T11: 87 87 // 此委托封裝的方法的第十一個參數的類型。 88 88 // 89 89 // T12: 90 90 // 此委托封裝的方法的第十二個參數的類型。 91 91 // 92 92 // T13: 93 93 // 此委托封裝的方法的第十三個參數的類型。 94 94 // 95 95 // T14: 96 96 // 此委托封裝的方法的第十四個參數的類型。 97 97 // 98 98 // T15: 99 99 // 此委托封裝的方法的第十五個參數的類型。 100 100 // 101 101 // T16: 102 102 // 此委托封裝的方法的第十六個參數的類型。 103 103 public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); 104 104 } 系統封裝-最多16個參數

實例化:

1             //接受0到16個參數的  無返回值 泛型委托
2             Action act1 = () => Console.WriteLine("123"); //1
3             Action<string> act2 = t => { };//2
4             Action<Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long> act3 = null;//3

 

4.2.  Func---有返回值---看out就看得出來啦!

1 namespace System 2 { 3 // 摘要: 4 // 封裝一個不具有參數但卻返回 TResult 參數指定的類型值的方法。 5 // 6 // 類型參數: 7 // TResult: 8 // 此委托封裝的方法的返回值類型。 9 // 10 // 返回結果: 11 // 此委托封裝的方法的返回值。 12 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 13 public delegate TResult Func<out TResult>(); 14 } 無參數,有一個返回值 1 namespace System 2 { 3 // 摘要: 4 // 封裝一個具有一個參數並返回 TResult 參數指定的類型值的方法。 5 // 6 // 參數: 7 // arg: 8 // 此委托封裝的方法的參數。 9 // 10 // 類型參數: 11 // T: 12 // 此委托封裝的方法的參數類型。 13 // 14 // TResult: 15 // 此委托封裝的方法的返回值類型。 16 // 17 // 返回結果: 18 // 此委托封裝的方法的返回值。 19 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 20 public delegate TResult Func<in T, out TResult>(T arg); 21 } 一個in,一個out 1 namespace System 2 { 3 // 摘要: 4 // 封裝一個方法,該方法具有 16 個參數,並返回 TResult 參數所指定的類型的值。 5 // 6 // 參數: 7 // arg1: 8 // 此委托封裝的方法的第一個參數。 9 // 10 // arg2: 11 // 此委托封裝的方法的第二個參數。 12 // 13 // arg3: 14 // 此委托封裝的方法的第三個參數。 15 // 16 // arg4: 17 // 此委托封裝的方法的第四個參數。 18 // 19 // arg5: 20 // 此委托封裝的方法的第五個參數。 21 // 22 // arg6: 23 // 此委托封裝的方法的第六個參數。 24 // 25 // arg7: 26 // 此委托封裝的方法的第七個參數。 27 // 28 // arg8: 29 // 此委托封裝的方法的第八個參數。 30 // 31 // arg9: 32 // 此委托封裝的方法的第九個參數。 33 // 34 // arg10: 35 // 此委托封裝的方法的第十個參數。 36 // 37 // arg11: 38 // 此委托封裝的方法的第十一個參數。 39 // 40 // arg12: 41 // 此委托封裝的方法的第十二個參數。 42 // 43 // arg13: 44 // 此委托封裝的方法的第十三個參數。 45 // 46 // arg14: 47 // 此委托封裝的方法的第十四個參數。 48 // 49 // arg15: 50 // 此委托封裝的方法的第十五個參數。 51 // 52 // arg16: 53 // 此委托封裝的方法的第十六個參數。 54 // 55 // 類型參數: 56 // T1: 57 // 此委托封裝的方法的第一個參數類型。 58 // 59 // T2: 60 // 此委托封裝的方法的第二個參數類型。 61 // 62 // T3: 63 // 此委托封裝的方法的第三個參數類型。 64 // 65 // T4: 66 // 此委托封裝的方法的第四個參數類型。 67 // 68 // T5: 69 // 此委托封裝的方法的第五個參數的類型。 70 // 71 // T6: 72 // 此委托封裝的方法的第六個參數的類型。 73 // 74 // T7: 75 // 此委托封裝的方法的第七個參數的類型。 76 // 77 // T8: 78 // 此委托封裝的方法的第八個參數的類型。 79 // 80 // T9: 81 // 此委托封裝的方法的第九個參數的類型。 82 // 83 // T10: 84 // 此委托封裝的方法的第十個參數的類型。 85 // 86 // T11: 87 // 此委托封裝的方法的第十一個參數的類型。 88 // 89 // T12: 90 // 此委托封裝的方法的第十二個參數的類型。 91 // 92 // T13: 93 // 此委托封裝的方法的第十三個參數的類型。 94 // 95 // T14: 96 // 此委托封裝的方法的第十四個參數的類型。 97 // 98 // T15: 99 // 此委托封裝的方法的第十五個參數的類型。 100 // 101 // T16: 102 // 此委托封裝的方法的第十六個參數的類型。 103 // 104 // TResult: 105 // 此委托封裝的方法的返回值類型。 106 // 107 // 返回結果: 108 // 此委托封裝的方法的返回值。 109 public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); 110 } 系統最多16個in參數

不過,不管怎麼變,Func的最後一個始終都時out,因為它時有返回值的呗!

1 //注意:這是一個新的類型,類型的不同包括了參數的個數的哦. 2 public delegate TResult ; 3 Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, out TResult> 4 (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, 5 T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17); 如果16個參數不夠的話
1 //接受0到16個參數的  帶返回值 泛型委托
2             Func<int> func1 = () => DateTime.Now.Millisecond;//4--返回int類型
        //下面都返回string類型 3 Func<int,
           string> func2 = t => DateTime.Now.Millisecond.ToString();//5 4 Func<Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long,
string> func3 = null;//6 5 //調用自己寫的,17個參數 6 Func<Student, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long,
          string> func4 = null;//6

 

5  擴展方法:  靜態類的靜態方法第一個參數加上 this.(靜態類不一定要加上static,只要有靜態方法的類就是靜態類)

 1     /// <summary>
 2     /// 靜態類的靜態方法,第一個參數前面加上this
 3     /// </summary>
 4     public static class ExtendTest
 5     {
 6         /// <summary>
 7         /// 轉成int  失敗給0寫日志
 8         /// </summary>
 9         /// <param name="sNumber"></param>
10         /// <returns></returns>
11         public static int ToInt(this string sNumber)
12         {
13             int iNumber = 0;
14             if (int.TryParse(sNumber, out iNumber))
15             {
16                 return iNumber;
17             }
18             else
19             {
20                 Console.WriteLine("{0} 轉換失敗,給出默認值", sNumber);
21                 return 0;
22             }
23         }
24 
25         public static void Study(this Student student)
26         {
27             Console.WriteLine("1234");
28         }
29 
30         public static void StudyVip(this Student student)
31         {
32             Console.WriteLine("1234");
33         }
34 
35         public static void ConsoleShow(this object oValue)
36         {
37             Console.WriteLine(oValue);
38         }
39 
40     }

 

調用:  就像給某個類添加了一個方法一樣,所以才叫擴展方法啊!

 1           string sNumber = "123345";
 2                 ExtendTest.ToInt(sNumber);//普通調用--返回一個int
 3                 sNumber.ToInt();//擴展方法調用--返回一個int
 4 
 5                 Student student = new Student()
 6                 {
 7                     Name = "天道無情(387-天道無情-男)"
 8                 };
 9                 student.StudyVip();
10                 student.Study();
11                 student.ConsoleShow();

不過,擴展方法並非給this 修飾的類添加了一個方法,而是通過this添加了一個紐帶.

當我們調用擴展方法時,還是進入了我們自己寫的方法裡.

只不過它看起來像時我們給一個類注入了一個方法而已.(這裡用注入很形象的形容)

記住:擴展方法時寫在一個外部的靜態類裡,並且是一個靜態方法,參數類型前加this.

 

6. Linq 查詢

1 private static List<Student> GetStudentList() 2 { 3 #region 初始化數據 4 List<Student> studentList = new List<Student>() 5 { 6 new Student() 7 { 8 Id=1, 9 Name="Answer(學委-answer-男)", 10 Age=25, 11 ClassId=2 12 }, 13 new Student() 14 { 15 Id=2, 16 Name=" LTS_信仰I(196-LTS_信仰I-男-深圳)", 17 Age=36, 18 ClassId=1 19 }, 20 new Student() 21 { 22 Id=3, 23 Name="ObjectIsNotFound", 24 Age=24, 25 ClassId=2 26 }, 27 new Student() 28 { 29 Id=4, 30 Name="落單的候鳥", 31 Age=25, 32 ClassId=2 33 }, 34 new Student() 35 { 36 Id=1, 37 Name="夜的樂章", 38 Age=31, 39 ClassId=2 40 }, 41 new Student() 42 { 43 Id=1, 44 Name="知心dě朋友=(357-傑仔-男-廣州)", 45 Age=18, 46 ClassId=2 47 }, 48 new Student() 49 { 50 Id=1, 51 Name="我", 52 Age=33, 53 ClassId=2 54 }, 55 new Student() 56 { 57 Id=1, 58 Name="小逸", 59 Age=28, 60 ClassId=2 61 }, 62 new Student() 63 { 64 Id=1, 65 Name="季雨林", 66 Age=27, 67 ClassId=2 68 }, 69 new Student() 70 { 71 Id=1, 72 Name="dean", 73 Age=34, 74 ClassId=2 75 }, 76 new Student() 77 { 78 Id=1, 79 Name="yup_h", 80 Age=21, 81 ClassId=1 82 } 83 }; 84 #endregion 初始化數據 85 return studentList; 86 } Linq用到的數據

普通程序員一般會想的方法:

 1             List<Student> studentList = GetStudentList();
 2             {
 3                 List<Student> targetList = new List<Student>();
 4                 foreach (var item in studentList)
 5                 {
 6                     if (item.Age > 25)
 7                     {
 8                         targetList.Add(item);
 9                     }
10                 }
11             }

Linq查詢和Lambda表達式查詢:

1 // 2 // 摘要: 3 // 基於謂詞篩選值序列。 4 // 5 // 參數: 6 // source: 7 // 要篩選的 System.Collections.Generic.IEnumerable<T>。 8 // 9 // predicate: 10 // 用於測試每個元素是否滿足條件的函數。 11 // 12 // 類型參數: 13 // TSource: 14 // source 中的元素的類型。 15 // 16 // 返回結果: 17 // 一個 System.Collections.Generic.IEnumerable<T>,包含輸入序列中滿足條件的元素。 18 // 19 // 異常: 20 // System.ArgumentNullException: 21 // source 或 predicate 為 null。 22 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); Where

注:Where本身是一個擴展方法.

Lambda

 1            {
 2                 Console.WriteLine("**************************");
 3                 var targetList = studentList.Where<Student>(t => t.Age > 25);//陳述式
 4                 foreach (var item in targetList)
 5                 {
 6                     Console.WriteLine(" {0}  {1}", item.Age, item.Name);
 7                 }
 8                 Console.WriteLine("**************************");
 9 

Linq

1                 Console.WriteLine("**************************");
2                 var list = from s in studentList
3                            where s.Age > 25
4                            select s;
5                 foreach (var item in list)
6                 {
7                     Console.WriteLine(" {0}  {1}", item.Age, item.Name);
8                 }

 

為了弄懂原理,請看下面:

7.    Lambda查詢模擬器:

this IEnumerable<TSource> source 是數據源

Func<TSource, bool> predicate 是查找的方法,第一個參數是傳入參數in,後一個是返回類型-用於判斷.

 1    public static class ElevenExtend
 2     {
 3         public static IEnumerable<TSource> ElevenWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
 4         {
 5             if (source == null) throw new Exception("null");
 6 
 7             List<TSource> tList = new List<TSource>();
 8 
 9             foreach (var item in source)
10             {
11                 if (predicate.Invoke(item)) //調用時會返回一個bool
12                     tList.Add(item);
13             }
14             return tList;
15         }
16     }
1         private static bool CheckStudentAge(Student student)
2         {
3             return student.Age > 25;
4         }

調用:        

1      Func<Student, bool> func = new Func<Student, bool>(CheckStudentAge); //t => t.Age > 25;
2         var targetListEleven = studentList.ElevenWhere<Student>(func);//陳述式
          foreach (var item in targetListEleven)
          {
               Console.WriteLine(" {0}  {1}", item.Age, item.Name);
          }

 

8. 其他的查詢:

1            {
2                 Console.WriteLine("**************************");
3                 var targetList = 
             studentList.Where<Student>(t => t.Age > 25 || t.Name.Contains("信仰") || new int[] { 1, 2 }.Contains(t.ClassId));//陳述式 4 foreach (var item in targetList) 5 { 6 Console.WriteLine(" {0} {1}", item.Age, item.Name); 7 } 8 }
1 // 2 // 摘要: 3 // 將序列中的每個元素投影到新表中。 4 // 5 // 參數: 6 // source: 7 // 一個值序列,要對該序列調用轉換函數。 8 // 9 // selector: 10 // 應用於每個元素的轉換函數。 11 // 12 // 類型參數: 13 // TSource: 14 // source 中的元素的類型。 15 // 16 // TResult: 17 // selector 返回的值的類型。 18 // 19 // 返回結果: 20 // 一個 System.Collections.Generic.IEnumerable<T>,其元素為對 source 的每個元素調用轉換函數的結果。 21 // 22 // 異常: 23 // System.ArgumentNullException: 24 // source 或 selector 為 null。 25 public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector); Select投影查詢
 1        {
 2                 var list = studentList.Select(s => new
 3                                       {
 4                                           IdAge = string.Format("{0}_{1}", s.Id, s.Age),
 5                                           Name = s.Name
 6                                       });
 7                 Console.WriteLine("**************************");
 8                 foreach (var student in list)
 9                 {
10                     Console.WriteLine("Name={0} Age={1}", student.Name, student.IdAge);
11                 }
12             }

對應的linq

 1        {
 2                 var list = from student in studentList
 3                            //where student.Age > 25
 4                            select new
 5                            {
 6                                IdAge = string.Format("{0}_{1}", student.Id, student.Age),
 7                                Name = student.Name
 8                            };//語法糖
 9 
10                 Console.WriteLine("**************************");
11                 foreach (var student in list)
12                 {
13                     Console.WriteLine("Name={0} Age={1}", student.Name, student.IdAge);
14                 }
15             }
 1       {
 2                 Console.WriteLine("**************************");
 3                 foreach (var student in studentList.Where<Student>(s => s.ClassId == 2 && s.Id < 4)
 4                                                    .Select<Student, Student>(s => 
           //Skip是跳過 Take是獲取
                                        new Student { Age = s.Age, Name = string.Format("{0}_{1}", s.Name, s.Id) }) 5 .OrderBy<Student, int>(s => s.Id) 6 .OrderByDescending<Student, int>(s => s.Age) 7 .Skip<Student>(1)//跳過1個 8 .Take<Student>(5))//獲取5個 9 { 10 Console.WriteLine("Name={0} Age={1}", student.Name, student.Age); 11 } 12 }

 注:linq查詢編譯後還是調用的Lambda表達式.

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