基礎拾遺---委託,匿名函式,lambda
前言:
C# 中的委託(Delegate)類似於 C 或 C++ 中函式的指標。委託是存有對某個方法的引用的一種引用型別變數。引用可在執行時被改變。委託(Delegate)特別用於實現事件和回撥方法。所有的委託都派生自 System.Delegate 類。把一個方法當作引數傳遞,讓其它方法進行呼叫執行。
1.委託的宣告
委託宣告決定了可由該委託引用的方法。委託可指向一個與其具有相同標籤的方法。
1.1.delegate
1.1.1. 0-23個引數,可以有返回值也可以沒有返回值
public delegate int MyDelegateEventHandler (string parm);
注:(1).此委託指向的方法必須是引數為string型別,返回型別為int型別的。其他宣告類比所得。
(2).EventHandler是c# 命名規範,當然我理解規範就是可以隨意啦。
(3).委託呼叫時必須判斷是否為null不然會報異常
(4).事件也是一種委託
1.1.2.委託的呼叫
MyDelegateEventHandler fun=new MyDelegateEventHandler(method); or MyDelegateEventHandler fun=method; // fun不為空,則呼叫回撥方法 if (fun!= null) { fun(val); } //fun?.Invoke(val); 簡化版本呼叫
1.1.3.委託的多播
每個委託都只包含一個方法呼叫,如果呼叫多個方法,就需要多次顯示呼叫這個委託。如果同一個委託呼叫多個方法,我們就可以用多播委託
public delegate void MyDelegate (); public voidMyMethod() { //# } public void MyMethod1() { //# } public void MyMethod2() { //# } MyDelegateEnventHander myDelegate; myDelegate=new MyDelegateEventHander(MyMethod); myDelegate+=new MyDelegateEventHander(MyMethod1); ........... //呼叫 myDelegate();
注:
1.委託物件可使用 "+" 運算子進行合併;
2."-" 運算子可用於從合併的委託中移除元件委託;
3.委託指定方法型別必須一致;
4.返回型別一般為void,但非必須;
5.GetInvocationList獲取委託索引
if (MyDelegate != null) System.Delegate[] dels = MyDelegate .GetInvocationList(); for (int i = 0; i < dels.Length; i++) { MyDelegate -= dels[i] as MethodDelegate; }
以上是利用GetInvocationList獲取委託索引的一個簡單應用。
1.2.Action
Action至少0個引數,至多16個引數,無返回值。
Action 表示無參,無返回值的委託 Action<int,string> 表示有傳入引數int,string無返回值的委託 Action<int,string,bool> 表示有傳入引數int,string,bool無返回值的委託 Action<int,int,int,int> 表示有傳入4個int型引數,無返回值的委託
public void Test<T>(Action<T> action,T p) { action(p); }
1.3.Func
Func至少0個引數,至多16個引數,根據返回值泛型返回。必須有返回值,不可void
Func是無返回值的泛型委託 Func<int> 表示無參,返回值為int的委託 Func<object,string,int> 表示傳入引數為object, string 返回值為int的委託 Func<object,string,int> 表示傳入引數為object, string 返回值為int的委託 Func<T1,T2,,T3,int> 表示傳入引數為T1,T2,,T3(泛型)返回值為int的委託
1.4.predicate
1.4.1.predicate 是返回bool型的泛型委託;
1.4.2.predicate<int> 表示傳入引數為int 返回bool的委託;
1.4.3.Predicate有且只有一個引數,返回值固定為bool;
public delegate bool Predicate<T> (T obj)
2.委託的例項化
2.1.delegate
public delegate int MyDelegateEventHandler (string parm) public int MyMethod(string parm) { //# } MyDelegateEventHandler MyDelegate=new MyDelegateEventHandler(MyMethod)
注:委託例項化的時候,委託物件必須使用 new 關鍵字來建立,且與一個特定的方法有關。委託引數中的方法不含引數。
2.2.Action的使用
public void Test<T>(Action<T> action, T p) { action(p); } private void Action(string s) { # } //呼叫 Test<string>(Action,"wyl");
2.3.Func的使用
public int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b) { return func(a, b); } private int Fun(int a, int b) { # } //呼叫 Test<int,int>(Fun,100,200)
2.4 委託實現氣泡排序
//定義物件 class Student { public string Name { get; private set; } public decimal Scores{ get; private set; } public Student(string name, decimal scores) { this.Name = name; this.Scores= scores; } public override string ToString() { return string.Format("{0},{1:C}",Name,Scores); } public static bool CompareScores(Student e1,Student e2) { return e1.Scores< e2.Scores; } } //利用委託實現冒泡 class BubbleScores { public static void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison) { bool swapped = true; do { swapped = false; for (int i = 0; i < sortArray.Count - 1; i++) { if (comparison(sortArray[i + 1], sortArray[i])) { T temp = sortArray[i]; sortArray[i] = sortArray[i + 1]; sortArray[i + 1] = temp; swapped = true; } } } while (swapped); } } //呼叫 Student[] students={new Student("wyl", 100),#}; BubbleSorter.Sort(students, Student.CompareScores); foreach(var student in students) Console.WriteLine(student);
3.匿名函式與lambda
3.1什麼是匿名函式
匿名函式是一個“內聯”語句或表示式,可在需要委託型別的任何地方使用。
可以使用匿名函式來初始化命名委託(無需取名字的委託),或傳遞命名委託(而不是命名委託型別,傳遞一個方法塊,而不是委託型別)[callback的方式]作為方法引數。
MyDelegate funDelegate = delegate(string s) { Console.WriteLine(s); }; funDelegate ("this is anonymous delegate");
3.2.lambda
lambda表示式實際上是一個匿名函式。編譯器在看到lambda之後會在類中自動定義一個新的私有方法。lambda必須匹配委託!其中lambda是從c#3.0後引用的
lambda的語法:
引數 => 方法體。
=>左邊是要傳入的引數,本例中是傳入一個Int型別的變數,=>右邊是具體的程式碼。
//如果不傳遞引數: ()=>Console.WriteLine("Hello World!") //傳遞一個引數: (int n)=>Console.WriteLine(n.ToString()) //或者去掉()和int 編譯器會自己推斷型別: n=>Console.WriteLine(n.ToString()) //傳遞多個引數: (int n ,int m)=>Console.WriteLine(n+m) //或者編譯器自己推斷型別: (n , m)=>Console.WriteLine(m+n)
4.綜上:
4.1.委託類似於 C++ 函式指標。
4.2.委託允許將方法作為引數進行傳遞。
4.3.委託可用於定義回撥方法。
4.4.委託可以連結在一起;多播。
4.5.方法不必與委託簽名完全匹配。
作者:王延領
出處:http://wyl1924.cnblogs.com
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。