昨天在和一位朋友讨论到委托与接口的问题,一开始我觉得很不可思议,这两个东西的概念怎么会混淆呢?要混淆也是接口和抽象类,委托和事件相混淆啊!但是着我的一个例子我马上意识到很有可能因为我将要表现的这个例子,让很多朋友混淆了委托与接口的用途.所以我想通过这篇文章试图说明白委托和接口的概念和用途,其实他们俩的差别还是很大的.

本文适合对委托和接口概念或用途不了解的朋友.

本文适合对委托和接口概念非常了解的朋友,并且欢迎各位朋友与Snake一起探讨有关这方面的知识. 本文不适合对委托和接口概念或用途了解一知半解(模糊)的朋友,这篇文章可能会对您产生误导,请千万别看. (本文原文是一篇没有好好排版过的email,我这里将会部分摘抄,部分改进,如果有什么地方您觉得莫名其妙,我将非常感谢您的指正!)

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

委托:

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

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

委托具有以下特点:

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

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

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

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

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

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

接口:

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

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

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

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

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

接口具有下列属性:

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

不能直接实例化接口。

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

接口不包含方法的实现。

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

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

正文开始

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

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

public int Calculate(Func<int, int, int> 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<Person>的类,我就拿本身继承它吧.

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

private int SortDelegate(Person p)  {    return p.ID;  }   public void TestMethod()   {  arr.Sort(new Func<Person, int>(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<Peron>) comp);

不能再继续举例子了,我承认我忽悠您了.这些看上去都可以的实现方法有本质的区别!

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

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

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

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

而接口的能力却是委托所不能企及的地方.它只能被方法藏在伸出,方法外一片蓝天而它却无能为力.如果让类比作一个国家,方法比作一个人,那么委托不就是深藏在人大脑内的处理方式的思维吗?不同的人,思维可以变,当乡下人看到城市中的高楼大厦不禁感叹,可乡下人在城市中生活习惯之后,高楼大厦又能怎样,他早已习以为常.

最后的论点有点晦涩,前面的例子具有误导性,所以本篇文章需要读懂个人认为不是很容易,毕竟个人对于表达能力还是比较不自信的.希望各位同仁海涵.

如果各位觉得本文污染了园子的首页,您可以毫不客气的点反对,如果您觉得还不错的话,我建议您可以考虑点击下推荐.

原文标题:写给会混淆委托和接口概念和用途的朋友们

链接:http://www.cnblogs.com/micone/archive/2010/08/02/1790680.html

本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/archive/2010/12/27/1917878.html,如需转载请自行联系原作者

详解.NET中容易混淆的委托与接口相关推荐

  1. 详解Objective-C中委托和协议

    Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于"委托"则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可 ...

  2. python混淆矩阵,详解使用python绘制混淆矩阵(confusion_matrix)

    这篇文章主要介绍了详解使用python绘制混淆矩阵(confusion_matrix),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学 ...

  3. 详解java中的final关键字

    概述 final 简介 final关键字可用于多个场景,且在不同场景具有不同的作用.首先,final是一个非访问修饰符,仅适用于变量,方法或类.下面是使用final的不同场景: 上面这张图可以概括成: ...

  4. java static 函数_详解java中的static关键字

    Java中的static关键字可以用于修饰变量.方法.代码块和类,还可以与import关键字联合使用,使用的方式不同赋予了static关键字不同的作用,且在开发中使用广泛,这里做一下深入了解. 静态资 ...

  5. java中的静态变量的作用域_详解JAVA中static的作用

    1.深度总结 引用一位网友的话,说的非常好,如果别人问你static的作用:如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的:如果是说 可以构成 静态代码块,那别人认为你还可以: 如果你说 ...

  6. 详解OpenCV中的Lucas Kanade稀疏光流单应追踪器

    详解OpenCV中的Lucas Kanade稀疏光流单应追踪器 1. 效果图 2. 源码 参考 这篇博客将详细介绍OpenCV中的Lucas Kanade稀疏光流单应追踪器. 光流是由物体或相机的运动 ...

  7. python操作目录_详解python中的文件与目录操作

    详解python中的文件与目录操作 一 获得当前路径 1.代码1 >>>import os >>>print('Current directory is ',os. ...

  8. python3中unicode怎么写_详解python3中ascii与Unicode使用

    这篇文章主要为大家详解python3中ascii与Unicode使用的相关资料,需要的朋友可以参考下# Auther: Aaron Fan ''' ASCII:不支持中文,1个英文占1个字节 Unic ...

  9. foreach php,详解PHP中foreach的用法和实例

    本篇文章介绍了详解PHP中foreach的用法和实例,详细介绍了foreach的用法,感兴趣的小伙伴们可以参考一下. 在PHP中经常会用到foreach的使用,而要用到foreach,就必须用到数组. ...

最新文章

  1. 逾期怎么处理_招商信用卡逾期三个月银行起诉我怎么处理?信用卡逾期一年半收到短信发到户籍所在地...
  2. 【转】DICOM的常用Tag分类和说明
  3. OpenJudge NOI 1.9 10:找最大数序列
  4. phpstduy8 redisClient 2.0 点不了_关于以太坊 2.0,你想知道的都在这里
  5. 漫画:唐玄奘教你横扫 AVL 树面试题无敌手!
  6. 如何开启php socket,如何用php实现websocket?
  7. 开源代码MyCommons
  8. (转)Singleton 单例模式(懒汉方式和饿汉方式)
  9. Layui-select 下拉框实现拼音全拼匹配/首字母模糊搜索
  10. wps怎么关闭修改痕迹_WPS文字中如何保留修改痕迹
  11. git项目文件上不显示图标的问题(绿色,红色)
  12. python scipy 密度函数 分位数 累计函数计算p值 卡方检验 t检验 F检验 假设检验 AB实验 显著性检验
  13. Birt时间参数添加My97日历控件
  14. Mathtype部分符号打不上去或部分符号点击后停止工作
  15. 任务管理器已被管理员禁用win10
  16. 信息系统项目管理师核心考点(五十四)配置项分类、状态与版本
  17. 定义电竞AI,引领数据体育-火星数据
  18. 学Android必须懂的
  19. CentOS下连VisualSVN服务器时报SSL handshake failed: SSL error: Key usage violation in certificate has been d
  20. 初入Linux,M35作业第二弹,牛刀小试

热门文章

  1. python画图角度_Python画图
  2. python实现一个简单的加法计算器_Python tkinter实现简单加法计算器代码实例
  3. 脱式计算机在线使用,脱式计算,
  4. java rocketmq消费_rocketmq消费负载均衡--push消费详解
  5. 农村电商谋定双创工程-李玉庭:互联网+农产品重整流通
  6. Java常用正则表达式
  7. 今天俺要说一说工厂方法模式(Factory)
  8. python控制窗口显示隐藏
  9. get中添加header
  10. Codeforces 769D k-Интересные пары чисел