首页 后端开发 C#.Net教程 c# 委托代码实例详解

c# 委托代码实例详解

Mar 07, 2017 am 11:05 AM
c# 委托

本文将通过实例解析对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)!



本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

使用 C# 的活动目录 使用 C# 的活动目录 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在这里,我们讨论 Active Directory 在 C# 中的介绍和工作原理以及语法和示例。

C# 序列化 C# 序列化 Sep 03, 2024 pm 03:30 PM

C# 序列化指南。这里我们分别讨论C#序列化对象的介绍、步骤、工作原理和示例。

C# 中的随机数生成器 C# 中的随机数生成器 Sep 03, 2024 pm 03:34 PM

C# 随机数生成器指南。在这里,我们讨论随机数生成器的工作原理、伪随机数和安全数的概念。

C# 数据网格视图 C# 数据网格视图 Sep 03, 2024 pm 03:32 PM

C# 数据网格视图指南。在这里,我们讨论如何从 SQL 数据库或 Excel 文件加载和导出数据网格视图的示例。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在这里,我们讨论 C# 中模式的介绍和前 3 种类型,以及其示例和代码实现。

C# 中的质数 C# 中的质数 Sep 03, 2024 pm 03:35 PM

C# 素数指南。这里我们讨论c#中素数的介绍和示例以及代码实现。

C# 中的阶乘 C# 中的阶乘 Sep 03, 2024 pm 03:34 PM

C# 阶乘指南。这里我们讨论 C# 中阶乘的介绍以及不同的示例和代码实现。

c#多线程和异步的区别 c#多线程和异步的区别 Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

See all articles