13.1 类和接口继承

13.2 定义接口

  • C#用 interface 关键字定义接口.接口中可定义方法,事件,无参属性和有参属性(C#的索引器),但不能定义任何构造器方法,也不能定义任何实例字段.

13.3 继承接口

  • C#编译器要求将实现接口的方法(简称为"接口方法")标记为public.
  • CLR要求将接口方法标记为 virtual .不将方法显式标记为 virtual ,编译器会将它们标记为 virtual 和 sealed;这会阻止派生类重写接口方法.将方法显式标记为 virtual,编译器就会将该方法标记为 virtual (并保持它的非密封状态),使派生类能重写它.
  1. static class Program
  2. {
  3. static void Main()
  4. {
  5. /****************************第一个例子*****************************/
  6. Base b = new Base();
  7. //用b的类型来调用Dispose,显示:"Base's Dispose"
  8. b.Dispose();
  9. //用b的对象的类型来调用Dispose,显示:"Base's Dispose"
  10. ((IDisposable)b).Dispose();
  11. /****************************第二个例子*****************************/
  12. Derived d = new Derived();
  13. //用d的类型来调用Dispose,显示:"Derived's Dispose"
  14. d.Dispose();
  15. //用d的对象的类型来调用Dispose,显示:"Derived's Dispose"
  16. ((IDisposable)d).Dispose();
  17. /****************************第三个例子*****************************/
  18. b = new Derived();
  19. //用b的类型来调用Dispose,显示:"Base's Dispose"
  20. b.Dispose();
  21. //用b的对象的类型来调用Dispose,显示:"Derived's Dispose"
  22. ((IDisposable)b).Dispose();
  23. }
  24. }
  25. //这个类派生自Object,它实现了Idisposable
  26. internal class Base : IDisposable
  27. {
  28. //这个方法隐式密封,不能被重写
  29. public void Dispose()
  30. {
  31. Console.WriteLine("Base's Dispose");
  32. }
  33. }
  34. //这个类派生自Base,它重新实现了IDisposable
  35. internal class Derived : Base, IDisposable {
  36. //这个方法不能重写Base的Dispose,
  37. //'new'表明该方法重新实现了IDisposable的Dispose方法
  38. new public void Dispose() {
  39. Console.WriteLine("Derived's Dispose");
  40. //注意,下面这行代码展示了如何调用基类的实现(如果需要的话)
  41. //base.Dispose();
  42. }
  43. }

总结:第三个例子第一条语句,是输出"Base's Dispose",还是输出"Derived's Dispose",取决于Base中的方法是否显式标记 virtual ,并且Derived中用 override 标记为重写. 换句话说,只有当基类允许重写,同时子类愿意重写时,通过基类的变量调用子类的实例时,才会调用子类的实现.

13.4 关于调用接口方法的更多探讨

和引用类型相似,值类型可实现零个或多个接口.但值类型的实例在转换为接口类型时必须装箱.

13.5 隐式和显式接口方法实现(幕后发生的事情)

  1. internal sealed class SimpleType : IDisposable
  2. {
  3. public void Dispose() { Console.WriteLine("public Dispose"); }
  4. void IDisposable.Dispose() { Console.WriteLine("IDisposable Dispose"); }
  5. }
  • C#要求公共Dispose方法同时是IDisposable的Dispose方法的实现.
  • 在C#中,将定义方法的那个接口的名称作为方法名前缀(例如 IDisposable.Dispose),就会创建显式接口方法实现(EIMI).c#中不允许在定义显式接口方法时指定可访问性(比如 public 或 private).但是编译器生成方法的元数据时,可访问性会自动设为private,防止其他代码在使用类的实例时直接调用接口方法.只有通过接口类型的变量才能调用接口方法.
  • EIMI方法不能标记为 virtual, 所以不能被重写.

13.6 泛型接口

13.7 泛型和接口约束

  • 可将泛型类型参数约束为多个接口.这样,传递的参数的类型必须实现全部接口约束.
  • 接口约束的第二个好处是传递值类型的实例时减少装箱.
  1. //向M方法传递Int32的实例时,不会发生装箱.
  2. private static Int32 M<T>(T t) where T : IComparable,IConvertible {...}
  3. //如果M向下面这样声明,传递Int32类型实例时会装箱
  4. private static Int32 M(IComparable t) {...}
  • C#编译器为接口约束生成特殊IL指令,导致直接在值类型上调用接口方法而不装箱.不用接口约束便没有其他办法让C#编译器生成这些IL指令.一个例外是如果值类型实现了一个接口方法,在值类型的实例上调用这个方法不会造成值类型的实例装箱.

13.8 实现多个具有相同方法名和签名的接口

要定义实现多个接口的类型,必须使用"显式接口方法实现"来实现这个类型的成员.

  1. public interface IWindow
  2. {
  3. object GetMenu();
  4. }
  5. public interface IRestaurant
  6. {
  7. object GetMenu();
  8. }
  9. //这个类型派生自System.Object,
  10. //并实现了IWindow和IRestaurant接口
  11. public sealed class MarioPizzeria : IWindow, IRestaurant
  12. {
  13. //这是IWindow的GetMenu方法的实现
  14. object IWindow.GetMenu() { ... }
  15. //这是IRestaurant的GetMenu方法的实现
  16. object IRestaurant.GetMenu(){ ... }
  17. //这个GetMenu方法是可选的,与接口无关
  18. public object GetMenu() { ... }
  19. }

代码在使用MarioPizzeria对象时必须将其转换为具体的接口才能调用所需的方法.

  1. MarioPizzeria mp = new MarioPizzeria();
  2. //这行代码调用 MarioPizzeria 的公共 GetMenu 方法.
  3. mp.GetMenu();
  4. //以下代码调用 MarioPizzeria 的 IWindow.GetMenu方法
  5. IWindow window = mp;
  6. window.GetMenu();
  7. //以下代码调用 MarioPizzeria 的 IRestaurant.GetMenu 方法
  8. IRestaurant restaurant = mp;
  9. restaurant.GetMenu();

13.9 用显式接口方法实现来增强编译时类型安全性

13.10 谨慎使用显式接口方法实现

EIMI最主要的问题:

  1. 没有文档解释类型具体如何实现一个EIMI方法,也没有"智能感知"支持.
  2. 值类型的实例在转换成接口时装箱.
  3. EIMI不能由派生类型调用

13.11 设计:基类还是接口

可定义接口,同时提供实现该接口的基类.

返回目录

<NET CLR via c# 第4版>笔记 第13章 接口的更多相关文章

  1. <NET CLR via c# 第4版>笔记 第19章 可空值类型

    System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5; Int32? y = null ...

  2. <NET CLR via c# 第4版>笔记 第18章 定制特性

    18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...

  3. <NET CLR via c# 第4版>笔记 第17章 委托

    17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...

  4. <NET CLR via c# 第4版>笔记 第16章 数组

    //创建一个一维数组 int[] myIntegers; //声明一个数组引用 myIntegers = new int[100]; //创建含有100个int的数组 //创建一个二维数组 doubl ...

  5. <NET CLR via c# 第4版>笔记 第12章 泛型

    泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...

  6. <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型

    5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...

  7. <NET CLR via c# 第4版>笔记 第6章 类型和成员基础

    6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...

  8. <NET CLR via c# 第4版>笔记 第7章 常量和字段

    7.1 常量 常量 是值从不变化的符号.定义常量符号时,它的值必须能够在编译时确定. 只能定义编译器识别的基元类型的常量,如果是非基元类型,需把值设为null. 常量的值直接嵌入代码,所以不能获取常量 ...

  9. <NET CLR via c# 第4版>笔记 第8章 方法

    8.1 实例构造器和类(引用类型) 构造引用类型的对象时,在调用类型的实例构造器之前,为对象分配的内存总是先被归零 .没有被构造器显式重写的所有字段都保证获得 0 或 null 值. 构造器不能被继承 ...

随机推荐

  1. poj 2449 Remmarguts' Date 求第k短路 Astar算法

    =.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstri ...

  2. Luogu P1314 聪明的质监员 二分答案

    题目链接 Solution 这个范围不是二分就是结论题就是数学题... 然后再看一会差不多就可以看出来有单调性所以就可以确定二分的解法了 二分那个$W$,用前缀和$O(n+m)$的时间来求出对答案的贡 ...

  3. iis发布,部署

    1.项目发布:选择iis:文件系统:文件路径:realese 2.iis添加: 3.host文件添加 问题1: 不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况.锁定 在全新安装 ...

  4. ajax实现highchart与数据库数据结合完整案例分析(三)---柱状折线图

    作者原创,未经博主允许,不可转载 在前面分析和讲解了用java代码分别实现饼状图和折线图,在工作当中,也会遇到很多用ajax进行异步请求 实现highchart. 先展示一下实现的效果图: 用ajax ...

  5. 【深度学习】Pytorch 学习笔记

    目录 Pytorch Leture 05: Linear Rregression in the Pytorch Way Logistic Regression 逻辑回归 - 二分类 Lecture07 ...

  6. 同一主机配置:vsftpd+pam+mysql

    两种情况: 1.vsftpd和MySQL不在同一台主机上 vsftpd服务器和MySQL服务器不在同一台主机上时,vsftpd服务器需要安装pam_mysql. 在指定用户认证时,vsftpd需要链接 ...

  7. UVa 1220 Hali-Bula的晚会(树的最大独立集)

    https://vjudge.net/problem/UVA-1220 题意: 公司里有n个人形成一个树状结构,即除了老板以外每个员工都有唯一的直属上司.要求选尽量多的人,但不能同时选择一个人和他的直 ...

  8. 软件测试&安全测试高峰论坛

    Nubia测试以及介绍 基于Cucumber的自动化测试平台 常见Web漏洞之XSS,主要HTML与JS基础.XSS的基础知识与挖掘方法.XSS的利用 自动化测试框架以及测试思路

  9. React Native 之轮播图swiper组件

    注释:swiper组件是第三方组件 所以在使用之前应该先在命令行安装,然后将第三方的模块引入(第三方模块地址:https://github.com/leecade/react-native-swipe ...

  10. C#完美读取CSV

    /// <summary>         /// 将DataTable中数据写入到CSV文件中         /// </summary>         /// < ...