您好,登錄后才能下訂單哦!
這篇“C#中的委托怎么聲明和使用”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“C#中的委托怎么聲明和使用”文章吧。
如果要給方法傳遞一個(gè)方法參數(shù)時(shí),就可以使用委托。要傳遞方法,就必須把方法的細(xì)節(jié)封裝在一鐘新類(lèi)型的對(duì)象中,即委托。委托是一種特殊類(lèi)型的對(duì)象,其特殊之處在于,我們以前定義的所有對(duì)象都包含數(shù)據(jù),而委托只包含一個(gè)或多個(gè)方法的地址。
.NET版本中,委托指向方法的地址。在C++中,函數(shù)指針是一個(gè)指向內(nèi)存位置的指針,但它不是類(lèi)型安全的。開(kāi)發(fā)者無(wú)法判斷這個(gè)指針實(shí)際指向什么,像參數(shù)和返回值等項(xiàng)就更不知道了。
.NET委托是類(lèi)型安全的類(lèi),它定義了返回類(lèi)型和參數(shù)的類(lèi)型。委托類(lèi)不僅包含對(duì)方法的引用,也可以包含對(duì)多個(gè)方法的引用。
使用委托和使用類(lèi)一樣,也需要經(jīng)過(guò)定義和實(shí)例化兩個(gè)步驟。首先必須定義要使用的委托,對(duì)于委托,定義它就是告訴編譯器這種類(lèi)型的委托表示哪種類(lèi)型的方法。然后,必須創(chuàng)建該委托的一個(gè)或多個(gè)實(shí)例才能使用。編譯器在后臺(tái)將創(chuàng)建表示該委托的一個(gè)類(lèi)。
定義委托的語(yǔ)法:
delegate void IntMethod(int x); //定義了一個(gè)委托IntMethod,指定該委托的每個(gè)實(shí)例都可以包含一個(gè)或多個(gè)方法的引用,引用的方法必須帶有一個(gè)int參數(shù),并返回void.
因?yàn)槎x委托基本上是定義一個(gè)新類(lèi),所以可以在定義類(lèi)的任何地方定義委托。也可以在委托的定義上使用修飾符:public,private,protected等。
委托派生自基類(lèi)System.MulticastDelegate,MulticastDelegate又派生自基類(lèi)System.Delegate.
類(lèi)有兩個(gè)不同的術(shù)語(yǔ):“類(lèi)”表示廣義的定義,“對(duì)象”表示;類(lèi)的實(shí)例。但委托只有一個(gè)術(shù)語(yǔ)。在創(chuàng)建委托的實(shí)例時(shí),所創(chuàng)建的實(shí)例仍稱(chēng)為委托。必須從上下文中確定委托的具體含義。
定義好委托之后,就可以創(chuàng)建它的一個(gè)實(shí)例,從而用它存儲(chǔ)特定方法的細(xì)節(jié)。
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(); }
委托在語(yǔ)法上總是接受一個(gè)參數(shù)的構(gòu)造函數(shù),這個(gè)參數(shù)就是委托引用的方法。這個(gè)方法必須匹配最初定義委托時(shí)的簽名。
使用委托實(shí)例的名稱(chēng),后面加上圓括號(hào),如果需要參數(shù)就必須在圓括號(hào)內(nèi)加上參數(shù)。
給委托實(shí)例提供圓括號(hào)和調(diào)用委托類(lèi)的Invoke()方法完全相同:
intMethod(x); intMethod.Invoke(x);
為了減少輸入量,只需要給委托實(shí)例傳遞方法地址的名稱(chēng)就可以,這稱(chēng)為委托推斷。
IntMethod intMethod = new IntMethod(Fun); IntMethod intMethod =Fun;
委托推斷可以在需要委托實(shí)例的任何地方使用。委托推斷也可以用于事件,因?yàn)槭录谖小#ㄊ录竺嫖恼掠薪榻B)
注意,使用委托可以調(diào)用任何類(lèi)型對(duì)象的方法,不管是靜態(tài)方法還是實(shí)例方法。
//先在一個(gè)類(lèi)中定義兩個(gè)方法: class MathOperations { public static double MultiplyByTwo(double value) { return value * 2; } public static double Square(double value) { return value * value; } }
//定義一個(gè)返回double類(lèi)型且?guī)в衐ouble類(lèi)型參數(shù)的委托 delegate double DoubleOp(double x); class Program { static void Main() { //實(shí)例化委托數(shù)組,和實(shí)例化類(lèi)的數(shù)組一樣 DoubleOp[] operations = { MathOperations.MultiplyByTwo, MathOperations.Square }; //遍歷數(shù)組,使用數(shù)組中的每個(gè)委托實(shí)例 for (int i = 0; i < operations.Length; i++) { Console.WriteLine("Using operations[{0}]:", i); //將委托實(shí)例作為參數(shù)傳遞給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中調(diào)用委托,執(zhí)行委托實(shí)例引用的方法 double result = action(value); Console.WriteLine( "Value is {0}, result of operation is {1}", value, result); } }
除了為每個(gè)參數(shù)和返回類(lèi)型定義一個(gè)委托類(lèi)型之外,還可以使用Action<T>和Func<T>委托。
泛型Action<T>委托表示引用一個(gè)void返回類(lèi)型的方法。這個(gè)委托類(lèi)存在不同的變體,可以傳遞最多16種不同的參數(shù)類(lèi)型。沒(méi)有泛型參數(shù)的Action類(lèi)調(diào)用沒(méi)有參數(shù)的方法。Action<in T>調(diào)用帶一個(gè)參數(shù)的方法,Action<in T1,in T2>調(diào)用帶兩個(gè)參數(shù)的方法,依次類(lèi)推。
Func<T>委托允許調(diào)用帶返回類(lèi)型的方法。與Action<T>類(lèi)似,F(xiàn)unc<T>也存在不同的變體,可以傳遞最多16種不同的參數(shù)類(lèi)型和一個(gè)返回類(lèi)型。Func<out TResult>委托類(lèi)型可以調(diào)用無(wú)參數(shù)且?guī)Х祷仡?lèi)型的方法。
下面使用Func<T>委托實(shí)現(xiàn)一個(gè)不使用委托很難編寫(xiě)的一個(gè)功能:給對(duì)象數(shù)組排序,如果對(duì)象是int或string這樣值類(lèi)型的對(duì)象會(huì)容易排序,如果是要排序很多自定義的類(lèi)型的對(duì)象,需要編寫(xiě)大量代碼。使用委托會(huì)減少代碼量。
定義包含比較方法的類(lèi):
BubbleSorter類(lèi)實(shí)現(xiàn)了一個(gè)泛型方法 Sort<T>,第一個(gè)參數(shù)是要排序的對(duì)象數(shù)組,第二個(gè)是一個(gè)委托,傳遞比較兩個(gè)對(duì)象的方法。這樣可以給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++) { //調(diào)用委托中引用的方法,比較兩個(gè)對(duì)象 if (comparison(sortArray[i + 1], sortArray[i])) { T temp = sortArray[i]; sortArray[i] = sortArray[i + 1]; sortArray[i + 1] = temp; swapped = true; } } } while (swapped); } }
定義自定義的一個(gè)類(lèi)
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; } }
客戶(hù)端代碼:
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執(zhí)行了自定義的Employee.CompareSalary方法 BubbleSorter.Sort(employees, Employee.CompareSalary); foreach (var employee in employees) { Console.WriteLine(employee); }
前面介紹的每個(gè)委托只包含一個(gè)方法的調(diào)用,委托也可以包含多個(gè)方法。這種委托稱(chēng)為多播委托。
如果調(diào)用多播委托,就可以按順序調(diào)用多個(gè)方法,但如果委托的簽名不是返回void,就只能得到委托調(diào)用的最后一個(gè)方法的結(jié)果。
使用+=添加方法,-=刪除方法。
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); } }
每次調(diào)用ProcessAndDisplayNumber方法,都會(huì)按順序調(diào)用action委托實(shí)例中的兩個(gè)方法。
輸出:
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
委托還可以使用+,-運(yùn)算符:
Action<double> operations1 = MathOperations.MultiplyByTwo; Action<double> operations2 = MathOperations.Square; Action<double> operations = operations1 + operations2; operations = operations - operations2;
多播委托包含一個(gè)逐個(gè)調(diào)用的委托集合。如果其中一個(gè)方法拋出異常,整個(gè)迭代就會(huì)停止。
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"); } }
委托只調(diào)用了第一個(gè)方法。因?yàn)榈谝粋€(gè)方法拋出異常,委托的迭代停止,不再調(diào)用Two()方法。
避免這個(gè)問(wèn)題,可以使用Delegate類(lèi)定義的GetInvocationList()方法,它返回一個(gè)Delegate對(duì)象數(shù)組:
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()方法可以為委托的每個(gè)方法傳遞不同的參數(shù),獲取每個(gè)方法的返回值。
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
使用匿名方法可以將方法體直接賦給委托實(shí)例,而不需要定義一個(gè)方法。
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,而是一段代碼,它前面是關(guān)鍵字delegate和參數(shù)列表。在使用匿名方法時(shí),可以使用外部變量。
匿名方法的優(yōu)點(diǎn)是減少了代碼量。使用匿名方法,代碼執(zhí)行速度并沒(méi)有加快。編譯器仍定義了一個(gè)方法,該方法只有一個(gè)自動(dòng)指定的名稱(chēng)。
使用匿名方法,必須遵守兩條規(guī)則:
(1).在匿名方法中不能使用跳轉(zhuǎn)語(yǔ)句(break,goto,continue)調(diào)到匿名方法的外部,外部的代碼也不能調(diào)到匿名方法內(nèi)部。
(2).匿名方法內(nèi)部不能訪問(wèn)不安全的代碼。也不能在匿名方法使用ref和out
如果需要匿名方法多次編寫(xiě)同一個(gè)功能時(shí),就不要用匿名方法了。
以上就是關(guān)于“C#中的委托怎么聲明和使用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。