1、接口对一组方法签名进行了统一命名。接口还能定义事件、无参属性和有参属性(C#的索引器)。

2、c#禁止接口定义任何一种静态成员。

3、C#编译器要求将实现接口的方法标记为public。CLR要求将接口的方法标记为virtual。不将方法显示标记为virtual,编译器会将它们标记为virtual和sealed;这会阻止派生类重写接口方法。将方法显式标记为virtual,编译器就会将方法标记为virtual,使派生类能重写它。派生类不能重写sealed的接口方法。但派生类可重新继承同一个接口,变为接口方法提供自己的实现:

 //这个类派生自Object,它实现了IDisposable
internal class Derived:Base,IDisposable{
//这个方法不能重写Base的Dispose,
//'new'表明该方法重新实现了IDisposable的Dispose方法
new public void Dispose(){
Console.WriteLine("Derived`s Dispose");
//注意,下面这行代码展示了如何调用基类的实现(如果需要的话)
//base.Dispose();
}
}

4、隐式和显示接口方法实现

类型加载到CLR中时,会为该类型创建并初始化一个方法表。在这个方法表中,类型引入的每个新方法都有对应的记录项;另外,还为该类型继承的所有虚方法添加了记录项。继承的虚方法既有继承层次结构中的各个基类型定义的,也有接口类型定义的。

internal sealed class SimpleType:IDisplsable{
public void Dispose(){
Console.WriteLine("Dispose");
}
}

类型的方法表将包含以下方法的记录项。

  • Object(隐式继承的基类)定义的所有虚实例方法。
  • IDisposable(继承的接口)定义的所有接口方法。本例只有一个方法,即Dispose,因为IDisposable接口只定义了这个方法。
  • SimpleType引入的新方法Dispose。

为了简化编程,C#编译器假定SimpleType引入的Dispose方法是对IDisposable的Dispose方法的实现。之所以这样假定,是由于Dispose方法的可访问性public,而接口方法的签名和新引入的方法完全一致。也就是说,两个方法具有相同的参数和返回类型。如果新的Dispose方法被标记为virtual,C#编译器仍然认为方法匹配接口方法。C#编译器将新方法和接口方法匹配起来之后,会生成元数据,指明SimpleType类型的方法表中的两个记录项应引用同一个实现。

现在重新SimpleType,以便于看出区别:

internal sealed class SimpleType:IDisposable{
public void Dispose(){ Console.WriteLine("public Dispose"); }
void IDisposable.Dispose(){ Console.WriteLine("IDisposable Dispose"); }
}

在C#中,将定义方法的那个接口的名称方法名前缀(例如IDisposable.Dispose),就会创建显示接口方法实现(EIMI)。注意,C#中不允许在定义显示接口方法时指定可访问性(比如public或private)。

5、泛型和接口约束

泛型类型参数约束的好处。

第一个好处在于,可将泛型类型参数约束为多个接口。这样一来,传递的参数的类型必须实现全部接口约束。

//M的类型参数T被约束为只支持同时实现了
//IComparable和IConvertitle接口的类型
private static Int32 M<T>(T t)where T:IComparable,IConvertible{
...
}

接口约束的第二个好处是传递值类型的实例时减少装箱。

C#编译器为接口约束生成特殊IL指令,导致直接在值类型上调用接口方法而不是装箱。不用接口约束便没有其他办法让C#编译器生成这些IL指令,如此一来,在值类型上调用接口方法总是发生装箱。一个例外是如果值类型实现了一个接口方法,在值类型的实例上调用这个方法不会造成值类型的实例装箱。

6、设计:基类还是接口

  • IS-A对比CAN-DO关系

   类型只能继承一个实现。如果派生类型和基类型建立不起IS-A关系,就不用基类而用接口。接口意味着CAN-DO关系。如果多种对象类型都“能”做某事,就为它们创建接口。例如,一个类型能将自己的实例转换为另一个类型(IConvertible),一个类型能序列化自己的实例(ISerializable)。注意,值类型必须从System.ValueType派生,所以不能从一个任意的基类派生。这时必须使用CAN-DO关系并定义接口。

  • 易用性
    基类派生比接口容易得多。
  • 一致性实现

  

  • 版本控制

CLR via c#读书笔记九:接口的更多相关文章

  1. CLR via c#读书笔记九:字符、字符串和文本处理

    1.在.NET Framework中,字符总是表示成16位unicode代码值(关于unicode.utf8等可以到http://www.ruanyifeng.com/blog/2007/10/asc ...

  2. [Clr via C#读书笔记]Cp13接口

    Cp13接口 类和接口继承 接口只提供签名,不提供实现:等效于契约:凡事能使用具名接口的地方都能够使用实现了的接口. 定义接口 定义很简单,FCL也提供了大量的现成接口供使用: 继承接口 类不能多继承 ...

  3. CLR via C# 读书笔记-21.托管堆和垃圾回收

    前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...

  4. Clr Via C#读书笔记---I/O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

  5. Clr Via C#读书笔记---计算限制的异步操作

    线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...

  6. Clr Via C#读书笔记---CLR寄宿和应用程序域

    #1 CLR寄宿: 开发CLR时,Microsoft实际是将他实现成包含在一个dll中的COM服务器.Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID.安装 ...

  7. Clr Via C#读书笔记---程序集的加载和反射

    #1 加载程序集 Assembly.Load: public class Assembly { public static Assembly Load(AssemblyName assemblyRef ...

  8. 读书笔记 C# 接口之浅析

    一.接口可以包含 属性.方法.事件和索引器: 二.接口不能被实例化: 三.一个类可以继承多个接口: 四.接口不能包含方法的实现: 五.继承接口的类必须实现接口中所有成员: 六.显式实现接口的成员,不能 ...

  9. CLR via C# 读书笔记-26.线程基础

    前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...

随机推荐

  1. 代码阅读:AFNetworking背后的思想

    1.一切皆文件:流与操作封装. 2.通信会话:

  2. vector size函数使用注意事项

    vector 的size函数返回vector大小,返回值类型为size_type,Member type size_type is an unsigned integral type,即无符号整数: ...

  3. window.jQuery || document.write("<script src='__PUBLIC__/assets/js/jquery.js'>"+"<"+"/script>")

    今天无意中看到这样一段代码 <script type="text/javascript"> window.jQuery || document.write(" ...

  4. 命令行参数技巧:__argc,__argv

    几个可以使用的全局变量: _CRTIMP extern int __argc; /* count of cmd line args */ _CRTIMP extern char ** __argv; ...

  5. 移动端 Touch 事件

    在移动端页面开发时,常常会用到touch事件,比如左滑右滑的轮播等.常用的触摸事件有touchstart,touchmove,touchend. 每个事件包含下面三个用于跟踪虎摸的属性: touche ...

  6. mvc读书笔记

    在mvc3的時候引入了Razor.Mvc4中默認的頂級目錄/controllers 保存那些處理URL請求的controller類/models 保存那些表示和操縱數據以及業務對象的類/views 保 ...

  7. Cesium.js点击事件

    创建viewer var viewer = new Cesium.Viewer('cesiumContainer'); 鼠标事件 var handler = new Cesium.ScreenSpac ...

  8. linux内存管理---虚拟地址、逻辑地址、线性地址、物理地址的区别(一)

    分析linux内存管理机制,离不了上述几个概念,在介绍上述几个概念之前,先从<深入理解linux内核>这本书中摘抄几段关于上述名词的解释: 一.<深入理解linux内核>的解释 ...

  9. Use PerfHUD ES to Do Frame Capture Android Game

    Author: http://www.cnblogs.com/open-coder/p/3898224.html Get Start This is short tutorial about how ...

  10. 初学pygame

    #Author:cljimport pygamepygame.display.set_mode((640,480),0,32)#设置窗口大小 返回的也是一个surface对象,resolution可以 ...