一起谈.NET技术,浅谈.Net中容易混淆的委托和接口

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:   本文适合对委托和接口概念非常了解的朋友,并且欢迎各位朋友与Snake一起探讨有关这方面的知识.本文不适合对委托和接口概念或用途了解一知半解(模糊)的朋友,这篇文章可能会对您产生误导,请千万别看.  在文章正式开始之前我需要将MSDN上对委托和接口的内容放上来,作为文章之基.  委托:  委托是一种定义方法签名的类型。

  本文适合对委托和接口概念非常了解的朋友,并且欢迎各位朋友与Snake一起探讨有关这方面的知识.本文不适合对委托和接口概念或用途了解一知半解(模糊)的朋友,这篇文章可能会对您产生误导,请千万别看.

  在文章正式开始之前我需要将MSDN上对委托和接口的内容放上来,作为文章之基.

  委托:

  委托是一种定义方法签名的类型。当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。您可以通过委托实例调用方法。

  委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。您可以创建一个自定义方法,当发生特定事件时某个类(例如 Windows 控件)就可以调用您的方法.

  委托具有以下特点:

  委托类似于 C++函数指针,但它们是类型安全的。

  委托允许将方法作为参数进行传递。

  委托可用于定义回调方法。

  委托可以链接在一起;例如,可以对一个事件调用多个方法。

  方法不必与委托签名完全匹配。有关更多信息,请参见在委托中使用变体(C#和 Visual Basic)。

  C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数。有关 Lambda 表达式的更多信息,请参见Anonymous Functions (C# Programming Guide)。

  接口:

  接口描述的是可属于任何类或结构的一组相关功能。接口可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。接口不能包含字段。接口成员一定是公共的。

  当类或结构继承接口时,意味着该类或结构为该接口定义的所有成员提供实现。接口本身不提供类或结构能够以继承基类功能的方式继承的任何功能。但是,如果基类实现接口,派生类将继承该实现。

  类和结构可以按照类继承基类或结构的类似方式继承接口,但有两个例外:

  类或结构可继承多个接口。

  类或结构继承接口时,仅继承方法名称和签名,因为接口本身不包含实现。

  接口具有下列属性:

  接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。

  不能直接实例化接口。

  接口可以包含事件、索引器、方法和属性。

  接口不包含方法的实现。

  类和结构可从多个接口继承。

  接口自身可从多个接口继承。

  正文开始

  在写这些文字的时候我又将以上的各个概念熟悉了一遍,以防自己把自己忽悠混淆了.所以不适合群众请尽快退散.另外如果您看完上面的定义和特征后就从两者的混淆中走了出来,您也可以尝试继续往下看.

  首先,关于委托的用法,我们可以这样使用:

public int Calculate(Func del){ int a = 1, b = 2; return del(a, b); }

  我们可以通过传不同的Func来改变整个方法的结果.

public int Add(int a, int b)
{ return a + b; } 
public int Sub(int a, int b)
{ return a - b; }
//调用方法如下 
public void TestMethod()
{ int result = Calculate(Add);
//the result is 3 int anotherResult = Calculate(Sub);//the result is -1 }

  首先我在Calculate方法中已经确定了2个数的值,并且包括在该方法当中.在输出结果的时候能明显看出传递的委托不同,其结果也不同.我们使用委托来改变方法的执行内容,我们不但可以改变其方法的内容,也可以在执行该方法的时候顺便做点什么(比如说做个日志记录).

  噢,可能您觉得二者容易混淆的地方在于..我还是举个例子比较好解释.

public interface ICal { int Calculate(int a, int b); }//有多个类实现了ICal接口. 
public class Add : ICal { public int Calculate(int a, int b){ return a + b; }} 
public class Sub : ICal { public int Calculate(int a, int b)
{ return a - b; }}//然后通过调用不同类来获取不同的方法 
public static void Main(){ ICal cal = new Add(); 
//ICal=new Sub(); Console.Write(cal.Calculate(1, 2)); }

  讲解一下,通过上面的例子我们可以知道在创建一个具有计算功能(Calculate)的接口ICal之后,产生了两个具有计算功能的具体类,分别是Add和Sub.为了要获得结果,我们创建了一个需要有计算功能的”坑”,并赋予能与此”坑”相匹配的类Add(或Sub),最后从该坑中调用Calculate的结果就行.

  貌似说的过去?好,那么我至少要让你觉得有个适用范围吧!看下面的例子.

  比如有个Person类的数组arr.这时候我们可以通过委托的方法实现arr的排序.可是系统怎么知道2个Person哪个排在前面,哪个该排在后面?这时候我们就可以传进一个委托来告诉系统Peron类的大小.

arr.Sort(p => { p.ID });

  该lambda表达式意思是丢给该Sort方法一个排序的Key(此key能够进行大小比较),那么Sort就可以根据此key来进行比较.那通过接口呢?首先得创建一个继承自IComparer的类,我就拿本身继承它吧.

  好吧,它本来是很麻烦的:

private int SortDelegate(Person p){ return p.ID; }
public void TestMethod(){ arr.Sort(new Func(SortDelegate)); }

  但是我们要承认C# 3.0带给我们的便利.

  现在,我们要让Person类实现接口的规定.

public int Compare(Person x, Person y){//假设person的ID是int类型 return x.ID -y.ID; }

  那么我们的实现方法就可能是这样:

arr.Sort((new Person() as IComparer) comp);

  首先我们看第一个委托例子:在Calculate时我们的委托被允许使用了该方法内的两个变量a,b从而改变了整个方法的结果.在整个过程中委托时很被动的,因为它不知道自己会在什么时候被触发.上面的例子很简单,使您没有这种感觉,而且前面说过在方法执行的时候当委托被触发我们可以干点别的,比如说做个日志记录什么的,此时接口有能力又不破坏方法本身运行结构,又能做日志记录吗?显然实现了接口的类只能重写一遍该方法.

  路人甲:那我在接口的实现中再调用一下原方法,最后在方法的前面或后面加入日志记录功能不就完了吗?

  Snake:杀鸡焉用宰牛刀?且不说再原方法的可行性,就算可行了,麻烦不说,万一这个方法执行有多个阶段,每个阶段都要日志记录呢?委托能深入方法,并且由方法控制它安放之地,让委托能起到关键作用,此时作为接口大哥的牛刀也剔不干净鸡骨上的肉哟~.

  其次说接口的优点.我们前面可以看到委托能深入方法,也就是说委托的关注群体是方法们,而接口关注的群体则是类们.接口让类必须实现相同签名的方法或属性,以便在程序中通过调用可变的方法.既然是因为类的关系,那么它的方法肯定是不可变的了,每个实现了该接口的类,即便功能差不多也要完完全全写一遍,但是类的地盘大,肚子里的墨水多,虽然在Add类中通过ICal可调用的方法也就一个Calculate(),但是在Calculate始终是Add类的子民,所以该Calculate方法可以调用Add类中所有能调用的资源.而如果是Sub类的话,它的子民Caculate可调用的资源又与Add类不尽相同,毕竟同是Calculate,国籍不同,文化和生活方式也不同嘛.

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
2月前
|
监控 Cloud Native 测试技术
.NET技术深度解析:现代企业级开发指南
每日激励:“不要一直责怪过去的自己,他曾经站在雾里也很迷茫”。我是蒋星熠Jaxonic,一名在代码宇宙中探索的极客旅人。从.NET Framework到.NET 8,我深耕跨平台、高性能、云原生开发,践行领域驱动设计与微服务架构,用代码书写技术诗篇。分享架构演进、性能优化与AI融合前沿,助力开发者在二进制星河中逐光前行。关注我,共探技术无限可能!
.NET技术深度解析:现代企业级开发指南
|
8月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
314 0
|
12月前
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
191 6
|
12月前
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
200 6
|
12月前
|
开发框架 监控 .NET
C#进阶-ASP.NET WebForms调用ASMX的WebService接口
通过本文的介绍,希望您能深入理解并掌握ASP.NET WebForms中调用ASMX WebService接口的方法和技巧,并在实际项目中灵活运用这些技术,提高开发效率和应用性能。
748 5
|
机器学习/深度学习 人工智能 Cloud Native
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台。本文深入解析 .NET 的核心优势,探讨其在企业级应用、Web 开发及移动应用等领域的应用案例,并展望未来在人工智能、云原生等方面的发展趋势。
256 3
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
129 3
|
12月前
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
350 5
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
447 0
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
234 7

热门文章

最新文章