欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【C#系列】浅谈委托和事件

程序员文章站 2022-06-24 09:44:02
本篇文章更适合具有一定开发经验,一定功底,且对底层代码有所研究的朋友!!! 本篇文章主要采用理论和代码实例相结合方式来论述委托和事件,涉及到一些边界技术,如软件架构的OCP原则(开-闭原则), 软件架构解耦,设计模式(Sender-Order)和事件驱动模型,有一定难度和深度,不适合初级者。 第一部 ......

【C#系列】浅谈委托和事件本篇文章更适合具有一定开发经验,一定功底,且对底层代码有所研究的朋友!!!

 

本篇文章主要采用理论和代码实例相结合方式来论述委托和事件,涉及到一些边界技术,如软件架构的OCP原则(开-闭原则),

软件架构解耦,设计模式(Sender-Order)和事件驱动模型,有一定难度和深度,不适合初级者。

第一部份   委托

关于委托内容,主要围绕下图来论述。

【C#系列】浅谈委托和事件

 一   委托是什么(what)

(一)委托产生的背景之一

1.我们先来假设这样一个情景需求:

   设计一个系统,使其满足如下条件:

   (1)当前,只有中国人和英国人使用该系统;

   (2)向系统输入用户名和相应的语言,将产生相应语言的问候语;

      【C#系列】浅谈委托和事件

  (3)后期,可能会有其他国家语言加入该系统(系统变化的部分) ;

 2.技术方案实现

关于技术方案实现,我们可以采用下图中的三种方式之一。

为了更好地叙述委托,我们分别实现三种技术方案,并找出它们的关系。

【C#系列】浅谈委托和事件

 2.1 一般实现

Code(控制台程序)

【C#系列】浅谈委托和事件
 1 using System;
 2 
 3 namespace DelegateDemo
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Console.WriteLine(GetGreetingContens("小王", "Chinese"));
10             Console.WriteLine(GetGreetingContens("Alan_beijing", "English"));
11             Console.WriteLine(GetGreetingContens("Linda", "Russian"));
12             Console.Read();
13         }
14 
15         //根据用户名和语言,获取问候语
16         public static string GetGreetingContens(string UserName, string Language)
17         {
18             //New 一个GreetToUsers对象
19             GreetToUsers greetToUsers = new GreetToUsers();
20             //当然,你也可以使用switch开发语句来代替如下的if......else......
21             if (Language == "Chinese")
22             {
23                 return greetToUsers.ChinesePeople(UserName);
24             }
25             else if (Language == "English")
26             {
27                 return greetToUsers.EnglishPeople(UserName);
28             }
29             else
30             {
31                 return "抱歉,当前系统只支持汉语与英语(Sorry, the current system only supports Chinese and English.)";
32             }
33         }
34     }
35 
36 
37 
38     //定义基本问候类和方法
39     public class GreetToUsers
40     {
41         //Chinese People
42         public string ChinesePeople(string UserName)
43         {
44             string GreetContents = "您好!" + UserName;
45             return GreetContents;
46         }
47 
48         //English People
49         public string EnglishPeople(string UserName)
50         {
51             string GreetContents = "Hello," + UserName + "!";
52             return GreetContents;
53         }
54     }
55 
56 }
View Code

 Result

【C#系列】浅谈委托和事件

分析

 【C#系列】浅谈委托和事件

2.2用接口实现

如上,我们分析了方案一中的问题,为了更好地解决方案一存在的问题,我们采用面向接口编程的形式来实现。

2.2.1  什么是面向接口编程?

面向接口编程,主要是解决软件架构设计中“动静问题”,即封装不变(静),剥离变化(抽出变化)。

 Code:

【C#系列】浅谈委托和事件
 1 using System;
 2 
 3 namespace DelegateDemo
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             GreetToChineseUsers greetToChinesUsers = new GreetToChineseUsers();
10             GreetToEnglishUsers greetToEnglishUsers = new GreetToEnglishUsers();
11             GreetToOtherUsers greetToOtherUsers = new GreetToOtherUsers();
12             //Chinse Users
13             IGreetToUsers iGreetToChineseUsers = greetToChinesUsers;
14             Console.WriteLine(iGreetToChineseUsers.CountryPeople("小王", "Chinese"));
15             //English Users
16             IGreetToUsers iGreetToEnglishUsers = greetToEnglishUsers;
17             Console.WriteLine(iGreetToEnglishUsers.CountryPeople("Alan_beijing", "English"));
18             //Other Users
19             IGreetToUsers iGreetToOtherUsers = greetToOtherUsers;
20             Console.WriteLine(iGreetToOtherUsers.CountryPeople("Linda", "Russian"));
21              
22             Console.Read();
23         }
24 
25         
26     }
27 
28     //系统输出问候语(变化的部分,语言为变化因子)
29     public interface IGreetToUsers 
30     {
31         string CountryPeople(string UserName,string Language);
32     }
33 
34 
35     //汉语用户类
36     public class GreetToChineseUsers:IGreetToUsers
37     {
38         //Chinese People
39         public string  CountryPeople(string UserName, string Language)
40         {
41             string GreetContents = "您好!" + UserName;
42             return GreetContents;
43         }
44     }
45     
46     //英语用户类
47     public class GreetToEnglishUsers : IGreetToUsers
48     {
49         //English People
50         public string CountryPeople(string UserName, string Language)
51         {
52             string GreetContents = "Hello," + UserName + "!";
53             return GreetContents;
54         }
55     }
56 
57     //其他用户类
58     public class GreetToOtherUsers : IGreetToUsers
59     {
60         //English People
61         public string CountryPeople(string UserName, string Language)
62         {
63             return "Sorrry,当前系统只支持汉语与英语";
64         }
65     }
66 
67 }
View Code

result

【C#系列】浅谈委托和事件

分析:

(1)如上,我们将变化因子"语言"剥离出来,形成接口,以后只要每增加一个语言,只需实现接口即可,满足了OCP原则,基本解决了方案一中存在的问题;

(2)如上代码只是为了演示面向接口编程这个功能,并不完善,感兴趣的读者,可自行完善(如将语言定义为枚举类型等);

【C#系列】浅谈委托和事件方案二中的代码,细心的读者会发现,Main方法中new了三个对象,假若以后系统有300门语言,那岂不New 300个类,这样的话,也不利于代码维护呀,怎么解决这个问题呢?(提示一下,采用设计模式抽象工厂即可解决该问题)

2.3 用委托实现

在这里,没接触过委托的读者,先跳过这部分,往下读,看完(三)怎样使用委托(How to use)后,再来看本部分。

 Code

【C#系列】浅谈委托和事件
 1 using System;
 2 
 3 namespace DelegateDemo
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             //根据语言判断,传递哪个方法的参数
10             Console.WriteLine("------------请输入用户名------------");
11             string UserName = Console.ReadLine();
12             Console.WriteLine("------------请输入语言------------");
13             string Language = Console.ReadLine();
14             Console.WriteLine("------------输出结果------------");
15             GreetToUsers greetToUsers = new GreetToUsers();
16             if (Language == "Chinese")
17             {
18                Console.WriteLine(GetGreetingContents(UserName, greetToUsers.ChinesePeople));
19             }
20             else if (Language == "English")
21             {
22                 Console.WriteLine(GetGreetingContents(UserName, greetToUsers.EnglishPeople));
23             }
24             else
25             {
26                Console.WriteLine(GetGreetingContents(UserName, greetToUsers.OtherPeople));
27             }
28            Console.Read();
29         }
30         
31         
32 
33         public static string GetGreetingContents(string UserName,DelegateGetGreeting delegateGetGreeting)
34         {
35            return delegateGetGreeting(UserName);
36         }
37     }
38 
39     //定义委托
40     public delegate string DelegateGetGreeting(string UserName);
41 
42 
43     //定义基本问候类和方法
44     public  class GreetToUsers
45     {
46         //Chinese People
47         public string ChinesePeople(string UserName)
48         {
49             string GreetContents = "您好!" + UserName;
50             return GreetContents;
51         }
52 
53         //English People
54         public string EnglishPeople(string UserName)
55         {
56             string GreetContents = "Hello," + UserName + "!";
57             return GreetContents;
58         }
59         //非英非汉
60         public string OtherPeople(string UserName)
61         {
62             return "Sorrry,当前系统只支持汉语与英语";
63         }
64     }
65 
66 }
View Code

 Result

【C#系列】浅谈委托和事件

 2.3 分析上述三种实现方案的关系

通过上诉三种方式的比较,我们容易得出委托的如下结论:

(1)抽象方法,屏蔽方法细节,调用只需传递方法名字即可;

(2)能够实现程序的解耦,松耦合(在方案一中,GetGreetingContens方法体内new了GreetToUsers对象,强耦合)

【C#系列】浅谈委托和事件

(3)委托一般扮演中间者的角色,这功能在委托事件中体现非常明显(第二部分 事件 将详细论述)

如我们在租房子时,可以直接找房东(技术实现的一般方法,强耦合,让租房者和房东直接联系),也可找中介(技术实现的委托,松耦合,租房者通过中介来与房东联系)

 【C#系列】浅谈委托和事件

2.4 委托背景概述

委托的重要产生背景,就是事件驱动模型(关于什么是事件和事件驱动,在本文第二部份 事件 论述)。

(二) 委托定义

 用delegate关键字定义委托(注意,委托是没有方法体的,类似接口里面的方法),在定义委托前,必须明确两个问题:

1.委托将要绑定的方法;

2.委托的形参类型,形参个数和委托的返回值必须与将要绑定的方法的形参类型,形参个数和返回值一致;

(三)相关概念

委托涉及的相关概念有函数指针,类型安全性、事件、Lambda表达式等

1.函数指针:在C++中,指针的一个类别,主要指向函数(变量指针,主要指向变量地址),可以把C#中的委托理解为函数指针;

2.类型安全性:在C++中,我们都知道指针是类型不安全的(返回值,返回类型和什么时候返回,这些都是未知的),而委托是类型安全的;

3.事件:可以把事件理解为委托的一种特例(在本文第二部份 事件 论述)

4.Lambda表达式:委托与Lambd表达式相结合,实现高效编程,与Jquery的“较少代码做更多的事”类似,委托与Lambda,Linq相结合,使较短代码就能实现比较复杂的功能(在本篇文章中不讲解Lambda与Lambda树,将在后续文章中讲解)

(四)委托组成

大致分为两部分:声明委托和注册方法(也叫绑定方法)

1.声明委托

用delegate声明;

2.绑定方法

绑定具体方法,传递方法名称;

(五) 委托种类

委托种类,一般分为多播委托和单播委托

1.单播委托:绑定单个方法

2.绑定多个方法

(六) 委托操作

1.绑定方法

2.解绑方法

二  委托能解决什么问题(Can do)

1.避免核心方法中存在大量的if....else....语句(或swich开关语句);

2.满足程序设计的OCP原则;

3.使程序具有扩展性;

4.绑定事件;

5.结合Lambda表达式,简化代码,高效编程;

6.实现程序的松耦合(解耦),这个在事件(event)中体现比较明显;

三  怎么使用委托(How to use)(本篇文章不谈匿名委托,匿名委托具体内容,将在Lambda章节讲解)

(一)委托的基本构成

通常地,使用委托的步骤与使用类的步骤是一样的。大致分为两步:定义委托和绑定方法(传递方法)

1.定义委托

用delegate关键字定义委托(注意,委托是没有方法体的,类似接口里面的方法),在定义委托前,必须明确两个问题:

(1).委托将要绑定的方法;

(2).委托的形参类型,形参个数和委托的返回值必须与将要绑定的方法的形参类型,形参个数和返回值一致;

public delegate  委托返回类型  委托名(形参)

例子:如上我们委托将要表示系统输出的问候语

a.委托将要绑定的方法

 public string ChinesePeople(string UserName)
        {
            string GreetContents = "您好!" + UserName;
            return GreetContents;
        }

        //English People
        public string EnglishPeople(string UserName)
        {
            string GreetContents = "Hello," + UserName + "!";
            return GreetContents;
        }
        //非英非汉
        public string OtherPeople(string UserName)
        {
            return "Sorrry,当前系统只支持汉语与英语";
        }

b.由如上方法可看出,方法的返回类型为string,方法有一个string类型的形参,在定义委托时,与其保持一致即可

//定义委托
public delegate string DelegateGetGreeting(string UserName);

2.绑定方法

使用委托时,将方法名字作为参数传递给委托即可

1 GreetToUsers greetToUsers = new GreetToUsers();
2 GetGreetingContents(UserName, greetToUsers.ChinesePeople)

(二)委托绑定方法

1.绑定单个方法

绑定单个方法,将单个方法名字传给委托即可

【C#系列】浅谈委托和事件
 1 static void Main(string[] args)
 2         {
 3             //根据语言判断,传递哪个方法的参数
 4             Console.WriteLine("------------请输入用户名------------");
 5             string UserName = Console.ReadLine();
 6             Console.WriteLine("------------请输入语言------------");
 7             string Language = Console.ReadLine();
 8             Console.WriteLine("------------输出结果------------");
 9             GreetToUsers greetToUsers = new GreetToUsers();
10             DelegateGetGreeting DGG;
11             if (Language == "Chinese")
12             {
13                 //绑定单个方法
14                 DGG = greetToUsers.ChinesePeople;
15                 Console.WriteLine(GetGreetingContents(UserName, DGG));
16             }
17             else if (Language == "English")
18             {
19                 DGG = greetToUsers.EnglishPeople;
20                 Console.WriteLine(GetGreetingContents(UserName, DGG));
21             }
22             else
23             {
24                 DGG = greetToUsers.OtherPeople;
25                 Console.WriteLine(GetGreetingContents(UserName, DGG));
26             }
27             
28             Console.Read();
29         }
View Code

另一种不太规范写法:不用GetGreetingContents(string UserName,DelegateGetGreeting delegateGetGreeting)方法

【C#系列】浅谈委托和事件
 1 static void Main(string[] args)
 2         {
 3             //根据语言判断,传递哪个方法的参数
 4             Console.WriteLine("------------请输入用户名------------");
 5             string UserName = Console.ReadLine();
 6             Console.WriteLine("------------请输入语言------------");
 7             string Language = Console.ReadLine();
 8             Console.WriteLine("------------输出结果------------");
 9             GreetToUsers greetToUsers = new GreetToUsers();
10             DelegateGetGreeting DGG;
11             if (Language == "Chinese")
12             {
13                 //绑定单个方法
14                 DGG = greetToUsers.ChinesePeople;
15                 Console.WriteLine(DGG(UserName));
16             }
17             else if (Language == "English")
18             {
19                 DGG = greetToUsers.EnglishPeople;
20                 Console.WriteLine(DGG(UserName));
21             }
22             else
23             {
24                 DGG = greetToUsers.OtherPeople;
25                 Console.WriteLine(DGG(UserName));
26             }
27             
28             Console.Read();
29         }
View Code

之所以不规范,主要是在项目中,不利于代码的模块化。

2.绑定多个方法(多播委托)

注意:绑定多个方法时,委托范围类型必须为void类型,否则只返回最后一个绑定的值。

 绑定多个方法,采用 += 绑定

【C#系列】浅谈委托和事件
 1 using System;
 2 
 3 namespace DelegateDemo
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9              
10             GreetToUsers greetToUsers = new GreetToUsers();
11             DelegateGetGreeting DGG;
12             
13             //绑定多个方法
14             DGG = greetToUsers.ChinesePeople;
15             DGG += greetToUsers.EnglishPeople;
16             DGG("小王");
17 
18             Console.Read();
19         }
20         
21         
22     }
23 
24     //定义委托
25     public delegate void DelegateGetGreeting(string UserName);
26 
27 
28     //定义基本问候类和方法
29     public  class GreetToUsers
30     {
31         //Chinese People
32         public void ChinesePeople(string UserName)
33         {
34             string GreetContents = "您好!" + UserName;
35             Console.WriteLine(GreetContents);
36         }
37 
38         //English People
39         public void EnglishPeople(string UserName)
40         {
41             string GreetContents = "Hello," + UserName + "!";
42             Console.WriteLine(GreetContents);
43         }
44         //非英非汉
45         public void OtherPeople(string UserName)
46         {
47             Console.WriteLine("Sorrry,当前系统只支持汉语与英语");
48         }
49     }
50 
51 }
52    
53 
54  
View Code

3.解绑方法

解载绑定的方法,采用 -= 解绑

【C#系列】浅谈委托和事件
 1 using System;
 2 
 3 namespace DelegateDemo
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9              
10             GreetToUsers greetToUsers = new GreetToUsers();
11             DelegateGetGreeting DGG;
12             
13             //绑定多个方法
14             DGG = greetToUsers.ChinesePeople;
15             DGG += greetToUsers.EnglishPeople;
16 
17             //解绑ChinesePeople方法
18             DGG-= greetToUsers.ChinesePeople;
19             DGG("小王");
20 
21             Console.Read();
22         }
23         
24         
25     }
26 
27     //定义委托
28     public delegate void DelegateGetGreeting(string UserName);
29 
30 
31     //定义基本问候类和方法
32     public  class GreetToUsers
33     {
34         //Chinese People
35         public void ChinesePeople(string UserName)
36         {
37             string GreetContents = "您好!" + UserName;
38             Console.WriteLine(GreetContents);
39         }
40 
41         //English People
42         public void EnglishPeople(st

                    
                
(0)
打赏 【C#系列】浅谈委托和事件 微信扫一扫

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

【C#系列】浅谈委托和事件
验证码: 【C#系列】浅谈委托和事件