本文將透過實例解析對c# 委託進行詳細介紹,具有很好的參考價值,下面跟著小編一起來看下吧
委託是一個類型。 C#中的委託是物件導向的,而且它是類型安全的 當建立委託實例的時候,建立的實例會包含一個呼叫列表,在呼叫列表中可以包含多個方法。每個方法稱作一個呼叫實體。呼叫實體可以是靜態方法,也可以是實例方法。如果是實例方法,則該呼叫實體包含呼叫該實例方法的實例。委託並不關心它所呼叫方法所屬的類,它只關心被呼叫方法與委託的類型是否相容。 以下是程式碼實例:
using System; namespace LycheeTest{ public delegate void D(int a, int b); public class Test { public D myDelegate; public Test() { myDelegate = new D(Show1); } private static void Show1(int a, int b) { Console.WriteLine("方法 Show1 被调用,两个实参相加的值是:{0}", a + b); } private void Show2(int a, int b) { Console.WriteLine("方法 Show2 被调用,两个实参相加的值是:{0}", a + b); } private void Show3(int a, int b) { Console.WriteLine("方法 Show3 被调用,两个实参相加的值是:{0}", a + b); } } public class Program { static void Main(string[] args) { Test myT = new Test(); myT.myDelegate(33, 22); Console.ReadKey(); } } }
這段程式碼示範的是最簡單的一種委託形式。 委託類型可以定義在類別的外部,也可以定義在類別的內部。 本段程式碼是定義在類別的外部。第 3 行程式碼定義的就是一個委託類型,委託類型的關鍵字是 delegate,關鍵字前方是委託類型的存取權修飾符。關鍵字後是委託類型的回傳類型,這個回傳類型規定與委託類型相容 的方法的回傳類型必須與之相同。傳回類型之後是委託類型的名稱。接下來是形參列表,它指定與委託類 型相容的方法的參數類型和個數必須與之相同。第 5 行程式碼定義了一個委託類型的變量,它是一個實例字段,存取權限是 public 的。注意委託類型欄位的存取權限一定要比委託類型的存取權限低或與委託類型的存取權限相同才可以。第 9 行、第 12 行和第 15 行程式碼定義了三個方法。其中第 9 行程式碼是靜態方法。因為這段程式碼示範的是最簡單的委託使用方法,所以只使用了其中的靜態方法。在第 6 行的建構方法中,實例化了委託類型的變量,注意為委託變量的呼叫列表添加方法,只需要向其構造方法中傳遞方法名稱即可。這是為委託添加呼叫方法的最基本的一種方法。第 21 行定義了 Test 類別的一個實例,然後第 22 行呼叫了類別的委託成員。在呼叫委託成員的時候,需要向其形參列表傳遞實參。這就是最基本的委託的使用方法。這段程式碼的執行結果如下:
方法Show1 被調用,兩個實參相加的值是:55
下面再介紹一種委託類型的使用方法,實例程式碼如下:
using System; namespace LycheeTest { public delegate void D(int a, int b); public class Test { public static void Show1(int a, int b) { Console.WriteLine("方法 Show1 被调用,两个实参相加的值是:{0}", a + b); } public void Show2(int a, int b) { Console.WriteLine("方法 Show2 被调用,两个实参相加的值是:{0}", a + b); } public void Show3(int a, int b) { Console.WriteLine("方法 Show3 被调用,两个实参相加的值是:{0}", a + b); } } public class Program { static void Main(string[] args) { Test myT = new Test(); D myDelegate = new D(Test.Show1); D myDelegate1 = new D(myT.Show2); D myDelegate2 = new D(myT.Show3); myDelegate(22, 33); myDelegate1(33, 44); myDelegate2(55, 66); Console.ReadKey(); } } }
這段程式碼取消了類別中的委託類型字段,而是將委託類型作為一個類別來看待。在包含入口點方法的類別中,首先第 17 行定義了 Test 類別的變數並做了實例化。因為要向委託傳遞類別的實例方法,所以必須有類別的實 例存在,才能引用類別的實例方法。第 18 行定義了一個委託類型的變量,並且實例化,這裡需要注意,因為委託並不是類別中的一個成員了, 所以向其構造方法傳遞靜態方法的時候,需要以類名引用。 第 19 行也定義了一個委託類型的變量,在傳遞實例方法的時候,需要以類別的實例來引用。第 20 行程式碼的情況同第 19 行程式碼一樣。在向委託傳遞方法的時候,需要傳遞方法名,而不需要方法的形參清單。第 21 行到第 23 行是對委託的調用,這時要為其傳遞方法的實參。這段程式碼的執行結果如下:
方法 Show1 被调用,两个实参相加的值是:55 方法 Show2 被调用,两个实参相加的值是:77 方法 Show3 被调用,两个实参相加的值是:121
#委託的存取修飾符
當委託位於類別的外部時,可以使用的存取修飾符包括public 和internal。如果什麼也不寫,預設是internal 的。當委託位於類別的內部時,可以使用的存取修飾符包括 public、protected、internal、protected
#using System; namespace LycheeTest{ public class Test { protected delegate void D(int a, int b); private delegate void D1(int a, int b); protected internal delegate void D2(int a, int b); internal delegate void D3(int a, int b); private D myD; private D1 myD1; private D2 myD2; private D3 myD3; public Test() { myD = new D(Show1); myD1 = new D1(Show1); myD2 = new D2(Show1); myD3 = new D3(Show1); } public static void Show1(int a, int b) { Console.WriteLine("方法 Show1 被调用,两个实参相加的值是:{0}", a + b); } public void Show2(int a, int b) { Console.WriteLine("方法 Show2 被调用,两个实参相加的值是:{0}", a + b); } public void Show3(int a, int b) { Console.WriteLine("方法 Show3 被调用,两个实参相加的值是:{0}", a + b); } public void Use() { myD(11, 12); myD1(22, 45); myD2(55, 78); myD3(345, 100); } } class Test1: Test { private D Test1D; private D2 Test1D2; private D3 Test1D3; public Test1() { Test1D = new D(Test.Show1); Test1D2 = new D2(Test.Show1); Test1D3 = new D3(Test.Show1); } public void Use1() { Test1D(22, 45); Test1D2(44, 45); Test1D3(77, 78); } } public class Program { static void Main(string[] args) { Test1 myT1 = new Test1(); myT1.Use(); myT1.Use1(); Console.ReadKey(); } } }
代码的第 4 行在类的内部定义了委托类型,它作为类的成员定义,访问权限是 protected,它可以被本类内部访问,也可以被派生类访问。代码的第 5 行定义的委托类型,访问权限是 private 的,它只可以被本类内部访问。代码的第 6 行定义的 protected internal 访问权限的委托类型,可以被本程序集访问, 还可以被派生类访问,而不管派生类位于哪个程序集。第 7 行定义的委托类型是 internal 的,它只可以被本程序集访问。因为所有这几种委托类型都可以被本类内部访问,所以第 10 行到第 13 行定义了它们的变量。第 12 行的实例构造方法中,对这四个委托类型的变量进行了实例化,并为它们的调用列表加入了方法 Show1。Show1 是一个静态方法,但是在类内部传入委托类型的构造方法时,不需要使用类名引用。第 27 行定义了实例方法,在方法内部调用了这四个委托,并为其传入实参。第 34 行代码又定义了一个类,它继承自基类 Test。因为基类中的委托类型只有 D、D2 和 D3 可以被派生类访问,所以第 35 行到第 37 行定义了它们的变量。注意,虽然它们和基类中的委托变量是同一种类型, 但是它们是不同的委托。在第 38 行的实例构造方法中,为这三个委托类型的变量创建实例,并为其调用列表加入方法,因为静态方法 Show1 也被派生类所继承,所以这里传入的方法名,可以使用类名引用,也可以不使用类名引用。 第 43 行定义了一个实例方法,方法内部调用了这三个委托,并为其传入实参。第 51 行定义了派生类的实例,然后调用实例方法Use和Use1。这段代码的执行结果如下:
方法 Show1 被调用,两个实参相加的值是:23 方法 Show1 被调用,两个实参相加的值是:67 方法 Show1 被调用,两个实参相加的值是:133 方法 Show1 被调用,两个实参相加的值是:445 方法 Show1 被调用,两个实参相加的值是:67 方法 Show1 被调用,两个实参相加的值是:89 方法 Show1 被调用,两个实参相加的值是:155
因为 D 和 D2 的访问权限被定义成了 protected 和 protected internal。所以下面来验证在其它程序集中是否可以访问它们。首先要将本段代码中的包含 Main 方法的类去掉,然后在它的项目属性中将它改变为类库。接下来新建一个控制台项目,并物理上引用这个类库。控制台项目的代码如下:
using System; using LycheeTest; namespace LycheeTest1{ class Program: Test { private D pD; private D2 pD2; public Program() { pD = new D(Show1); pD2 = new D2(Show1); } public void Use3() { pD(34, 33); pD2(12, 11); } static void Main(string[] args) { Program p = new Program(); p.Use3(); Console.ReadKey(); } } }
因为第 3 行代码的命名空间和类库的命名空间是两个独立的命名空间,它们的成员不位于同一个命名空间内。所以在一个命名空间内引用另一个命名空间的成员时,需要加上另一个命名空间的名称进行引用。 为了代码编写的方便,第 2 行代码首先引用了类库的命名空间。第 4 行代码定义了一个类,它继承自基类 Test。因为是派生类,所以对于委托类型 D 和 D2 都可以访 问。第 5 行代码和第 6 行代码分别定义了 D 和 D2 的两个变量。第 7 行的实例构造方法对这两个变量进行了实例化,并为其传入方法 Show1。因为 Show1 方法被继承了下来,所以这里不需要类名引用。第 11 行代码定义了一个实例方法,它的作用是调用这两个委托,并为其传入实参。第 16 行代码定义了本类的一个实例,并调用了实例方法 Use3。这段代码的执行结果如下:
方法 Show1 被调用,两个实参相加的值是:67 方法 Show1 被调用,两个实参相加的值是:23
类Test中的委托类型D2和D3都具有internal权限,现在来验证一下,对于一个同一程序集中的非派生类是否可以访问它们。首先将类库更改回控制台项目,然后增加一个类,这个类对于Test类来说是独立的。它们之间只是位于一个程序集内,彼此没有继承关系。代码如下:
using System; namespace LycheeTest { public class Test { protected delegate void D(int a, int b); private delegate void D1(int a, int b); protected internal delegate void D2(int a, int b); internal delegate void D3(int a, int b); private D myD; private D1 myD1; private D2 myD2; private D3 myD3; public Test() { myD = new D(Show1); myD1 = new D1(Show1); myD2 = new D2(Show1); myD3 = new D3(Show1); } public static void Show1(int a, int b) { Console.WriteLine("方法 Show1 被调用,两个实参相加的值是:{0}", a + b); } public void Show2(int a, int b) { Console.WriteLine("方法 Show2 被调用,两个实参相加的值是:{0}", a + b); } public void Show3(int a, int b) { Console.WriteLine("方法 Show3 被调用,两个实参相加的值是:{0}", a + b); } public void Use() { myD(11, 12); myD1(22, 45); myD2(55, 78); myD3(345, 100); } } class Test1 { private Test.D2 tD2; private Test.D3 tD3; public Test1() { tD2 = new Test.D2(Test.Show1); tD3 = new Test.D3(Test.Show1); } public void Use3() { tD2(34, 33); tD3(22, 21); } } public class Program { static void Main(string[] args) { Test1 myT1 = new Test1(); myT1.Use3(); Console.ReadKey(); } } }
这段代码中,原来的类Test没有进行修改。在第35行上,定义了一个类,它是一个相对于Test类来说独立的类。它们的关系仅限于同在一个程序集内。第 36 行代码和第 37 行代码定义了委托类型D2和D3的两个变量。这里需要注意,因为这两个类不是继承关系,所以要引用Test类中的这两个委托类型需要使用Test类的类名进行引用。第 38 行代码是实例构造方法,在构造方法中将委托实例化。实例化委托类型的时候,仍然需要使用类名引用委托类型名,传递的方法名也是如此。第 行42 定义了一个实例方法,它调用了委托,并为其传入了实参。第 49 行代码定义了类Test1的一个实例,然后第 61 行调用类的实例方法。这段代码的执行结果如下:
方法 Show1 被调用,两个实参相加的值是:67 方法 Show1 被调用,两个实参相加的值是:43
以上就是c# 委托代码实例详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!