<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
如果要給方法傳遞一個方法引數時,就可以使用委託。要傳遞方法,就必須把方法的細節封裝在一鍾新型別的物件中,即委託。委託是一種特殊型別的物件,其特殊之處在於,我們以前定義的所有物件都包含資料,而委託只包含一個或多個方法的地址。
.NET版本中,委託指向方法的地址。在C++中,函數指標是一個指向記憶體位置的指標,但它不是型別安全的。開發者無法判斷這個指標實際指向什麼,像引數和返回值等項就更不知道了。
.NET委託是型別安全的類,它定義了返回型別和引數的型別。委託類不僅包含對方法的參照,也可以包含對多個方法的參照。
使用委託和使用類一樣,也需要經過定義和範例化兩個步驟。首先必須定義要使用的委託,對於委託,定義它就是告訴編譯器這種型別的委託表示哪種型別的方法。然後,必須建立該委託的一個或多個範例才能使用。編譯器在後臺將建立表示該委託的一個類。
定義委託的語法:
delegate void IntMethod(int x); //定義了一個委託IntMethod,指定該委託的每個範例都可以包含一個或多個方法的參照,參照的方法必須帶有一個int引數,並返回void.
因為定義委託基本上是定義一個新類,所以可以在定義類的任何地方定義委託。也可以在委託的定義上使用修飾符:public,private,protected等。
委託派生自基礎類別System.MulticastDelegate,MulticastDelegate又派生自基礎類別System.Delegate.
類有兩個不同的術語:“類”表示廣義的定義,“物件”表示;類的範例。但委託只有一個術語。在建立委託的範例時,所建立的範例仍稱為委託。必須從上下文中確定委託的具體含義。
定義好委託之後,就可以建立它的一個範例,從而用它儲存特定方法的細節。
delegate void IntMethod(int x); static void Fun(int x) { Console.WriteLine(x); } static void Main() { int x = 40; IntMethod intMethod = new IntMethod(Fun); intMethod(x); Console.ReadKey(); }
委託在語法上總是接受一個引數的建構函式,這個引數就是委託參照的方法。這個方法必須匹配最初定義委託時的簽名。
使用委託範例的名稱,後面加上圓括號,如果需要引數就必須在圓括號內加上引數。
給委託範例提供圓括號和呼叫委託類的Invoke()方法完全相同:
intMethod(x); intMethod.Invoke(x);
為了減少輸入量,只需要給委託範例傳遞方法地址的名稱就可以,這稱為委託推斷。
IntMethod intMethod = new IntMethod(Fun); IntMethod intMethod =Fun;
委託推斷可以在需要委託範例的任何地方使用。委託推斷也可以用於事件,因為事件基於委託。(事件後面文章有介紹)
注意,使用委託可以呼叫任何型別物件的方法,不管是靜態方法還是實體方法。
//先在一個類中定義兩個方法: class MathOperations { public static double MultiplyByTwo(double value) { return value * 2; } public static double Square(double value) { return value * value; } }
//定義一個返回double型別且帶有double型別引數的委託 delegate double DoubleOp(double x); class Program { static void Main() { //範例化委託陣列,和範例化類的陣列一樣 DoubleOp[] operations = { MathOperations.MultiplyByTwo, MathOperations.Square }; //遍歷陣列,使用陣列中的每個委託範例 for (int i = 0; i < operations.Length; i++) { Console.WriteLine("Using operations[{0}]:", i); //將委託範例作為引數傳遞給ProcessAndDisplayNumber方法 ProcessAndDisplayNumber(operations[i], 2.0); ProcessAndDisplayNumber(operations[i], 7.94); ProcessAndDisplayNumber(operations[i], 1.414); Console.WriteLine(); } } static void ProcessAndDisplayNumber(DoubleOp action, double value) { //在ProcessAndDisplayNumber中呼叫委託,執行委託範例參照的方法 double result = action(value); Console.WriteLine( "Value is {0}, result of operation is {1}", value, result); } }
除了為每個引數和返回型別定義一個委託型別之外,還可以使用Action<T>和Func<T>委託。
泛型Action<T>委託表示參照一個void返回型別的方法。這個委託類存在不同的變體,可以傳遞最多16種不同的引數型別。沒有泛型引數的Action類呼叫沒有引數的方法。Action<in T>呼叫帶一個引數的方法,Action<in T1,in T2>呼叫帶兩個引數的方法,依次類推。
Func<T>委託允許呼叫帶返回型別的方法。與Action<T>類似,Func<T>也存在不同的變體,可以傳遞最多16種不同的引數型別和一個返回型別。Func<out TResult>委託型別可以呼叫無引數且帶返回型別的方法。
下面使用Func<T>委託實現一個不使用委託很難編寫的一個功能:給物件陣列排序,如果物件是int或string這樣值型別的物件會容易排序,如果是要排序很多自定義的型別的物件,需要編寫大量程式碼。使用委託會減少程式碼量。
定義包含比較方法的類:
BubbleSorter類實現了一個泛型方法 Sort<T>,第一個引數是要排序的物件陣列,第二個是一個委託,傳遞比較兩個物件的方法。這樣可以給Sort<T>方法,傳遞自定義的比較方法。
class BubbleSorter { static public 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); } }
定義自定義的一個類
class Employee { public Employee(string name, decimal salary) { this.Name = name; this.Salary = salary; } public string Name { get; private set; } public decimal Salary { get; private set; } public override string ToString() { return string.Format("{0}, {1:C}", Name, Salary); } public static bool CompareSalary(Employee e1, Employee e2) { return e1.Salary < e2.Salary; } }
使用者端程式碼:
Employee[] employees = { new Employee("Bugs Bunny", 20000), new Employee("Elmer Fudd", 10000), new Employee("Daffy Duck", 25000), new Employee("Wile Coyote", 1000000.38m), new Employee("Foghorn Leghorn", 23000), new Employee("RoadRunner", 50000) }; //Sort執行了自定義的Employee.CompareSalary方法 BubbleSorter.Sort(employees, Employee.CompareSalary); foreach (var employee in employees) { Console.WriteLine(employee); }
前面介紹的每個委託只包含一個方法的呼叫,委託也可以包含多個方法。這種委託稱為多播委託。
如果呼叫多播委託,就可以按順序呼叫多個方法,但如果委託的簽名不是返回void,就只能得到委託呼叫的最後一個方法的結果。
使用+=新增方法,-=刪除方法。
static void Main() { Action<double> operations = MathOperations.MultiplyByTwo; operations += MathOperations.Square; ProcessAndDisplayNumber(operations, 2.0); ProcessAndDisplayNumber(operations, 7.0); Console.WriteLine(); } static void ProcessAndDisplayNumber(Action<double> action, double value) { Console.WriteLine(); Console.WriteLine("ProcessAndDisplayNumber called with value = {0}", value); action(value); } class MathOperations { public static void MultiplyByTwo(double value) { double result = value * 2; Console.WriteLine("Multiplying by 2: {0} gives {1}", value, result); } public static void Square(double value) { double result = value * value; Console.WriteLine("Squaring: {0} gives {1}", value, result); } }
每次呼叫ProcessAndDisplayNumber方法,都會按順序呼叫action委託範例中的兩個方法。
輸出:
ProcessAndDisplayNumber called with value = 2 Multiplying by 2: 2 gives 4 Squaring: 2 gives 4 ProcessAndDisplayNumber called with value = 7 Multiplying by 2: 7 gives 14 Squaring: 7 gives 49
委託還可以使用+,-運運算元:
Action<double> operations1 = MathOperations.MultiplyByTwo; Action<double> operations2 = MathOperations.Square; Action<double> operations = operations1 + operations2; operations = operations - operations2;
多播委託包含一個逐個呼叫的委託集合。如果其中一個方法丟擲異常,整個迭代就會停止。
static void One() { Console.WriteLine("One"); throw new Exception("Error in one"); } static void Two() { Console.WriteLine("Two"); } static void Main() { Action d1 = One; d1 += Two; try { d1(); } catch (Exception) { Console.WriteLine("Exception caught"); } }
委託只呼叫了第一個方法。因為第一個方法丟擲異常,委託的迭代停止,不再呼叫Two()方法。
避免這個問題,可以使用Delegate類定義的GetInvocationList()方法,它返回一個Delegate物件陣列:
Action d1 = One; d1 += Two; Delegate[] delegates = d1.GetInvocationList(); foreach (Action d in delegates) { try { d(); } catch (Exception) { Console.WriteLine("Exception caught"); } }
輸出:
One Exception caught Two
使用GetInvocationList()方法可以為委託的每個方法傳遞不同的引數,獲取每個方法的返回值。
static int One(int x) { return x; } static int Two(int x) { return x; } static void Main() { Func<int,int> d1 = One; d1 += Two; Delegate[] delegates = d1.GetInvocationList(); Func<int, int> d2 = (Func<int, int>)delegates[0]; Console.WriteLine( d2(1)); Func<int, int> d3 = (Func<int, int>)delegates[1]; Console.WriteLine(d3(2)); Console.ReadKey(); }
輸出:
1 2
使用匿名方法可以將方法體直接賦給委託範例,而不需要定義一個方法。
static void Main() { string mid = ", middle part,"; Func<string, string> anonDel = delegate(string param) { param += mid; param += " and this was added to the string."; return param; }; Console.WriteLine(anonDel("Start of string")); }
上面程式碼不是把方法名賦給委託變數anonDel,而是一段程式碼,它前面是關鍵字delegate和參數列。在使用匿名方法時,可以使用外部變數。
匿名方法的優點是減少了程式碼量。使用匿名方法,程式碼執行速度並沒有加快。編譯器仍定義了一個方法,該方法只有一個自動指定的名稱。
使用匿名方法,必須遵守兩條規則:
如果需要匿名方法多次編寫同一個功能時,就不要用匿名方法了。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45