CLR不允许继承多个基类,但是可以继承多个接口。凡是能使用具名接口类型的实例的地方,都能使用实现了接口的一个类型的实例。 接口是对一组方法签名进行了统一命名,但不提供任何实现,而具体类则必须为继承的全部接口提供实现。

1. 定义接口

接口是用interface关键字定义对一组方法签名,接口名称一般以字母I开头;而且还可以为接口定义事件、索引器和属性,但禁止定义构造器和实例字段,也不能构造任何静态成员。例如:

public interface IShout
{
    public IShout();//×Error Interfaces cannot contain constructors 
    static void Shout1();//×Error The modifier 'static' is not valid for this item 
    void Shout();
    string Name { get; set; }
}

2. 接口方法

具体的类继承接口后要为接口中定义的方法提供实现。我们首先定义一个接口,然后再定义类来实现该接口。

public interface IIntroduce
     {
         void Shout();
         void Description();
     }

接口方法,即具体类中实现接口中定义的方法,它的实现要注意几点:

  • 接口方法必须是Public;
  • CLR要求将接口方法标记为virtual,否则编译器会自动标记为virtual和sealed。

public class Animal : IIntroduce
    {
        public void Shout()                     //接口方法为标记为virtual 
        {
            Console.WriteLine("Animal Shout.");
        }
        public virtual void Description()  //接口方法标记为virtual 
        {
            Console.WriteLine("Animal Description.");
        }
    }

查看IL代码:

  • 派生类可以使用New关键字为接口提供自己的实现。

public class Dog : Animal
   {
       public override void Description()//重写基类的接口方法 
       {
           Console.WriteLine("Dog Description!");
       }
   }

public class Cat : Animal, IIntroduce
   {
       public override void Description()//重写基类的接口方法 
       {
           Console.WriteLine("Cat Description!");
       }
       new public void Shout()//重新实现接口方法 
       {
           Console.WriteLine("Cat Shout.");
       }
   }

3. 显式接口实现

实现接口有隐式实现和显式实现两种方式。当多个接口中包含名称和签名都相同的方法时,要使用显示接口方法实现。

public interface IDemo1
   {
       void Func();
   }
   public interface IDemo2
   {
       void Func();
   }
   public class Demo : IDemo1, IDemo2
   {
       public void Func()
       {
           Console.WriteLine("Demo.Func()");
       }
       void IDemo1.Func()
       {
           Console.WriteLine("IDemo1.Func()");
       }
       void IDemo2.Func()
       {
           Console.WriteLine("IDemo2.Func()");
       }
   }

class Program
   {
       static void Main(string[] args)
       {
           Demo demo = new Demo();
           demo.Func();//调用Demo类中的公共方法Func()
           ((IDemo1)demo).Func(); //显式调用IDemo1中的Func()
           ((IDemo2)demo).Func(); //显式调用IDemo2中的Func()
           Console.Read();
       }
   }

调用结果:

显式接口实现要注意:

  • 不允许指定访问性,如Public等;查看元数据时会发现它自动标记为Private。
  • 不能标记为virtual。
  • 显式接口应该慎重使用,因为值类型的实例在转型为接口时会发生装箱,而且显式接口方法不能被派生类继承。

4.泛型接口

FCL提供了很多现成的接口如IComparable,同时提供了其泛型接口形式IComparable<T>.这样做能够编译时就检测类型从而提高了类型安全,而且减少了参数向object类型转换的装箱拆箱操作,提高了性能。

int x = 1;

IComparable y = "2";

y.CompareTo(x); //编译通过,运行时错误
IComparable<int> z = 3;
z.CompareTo(x); //编译通过,运行通过

5. 基类vs接口

  • 如果存在IS-A关系使用基类,存在CAN-DO关系,使用接口。
  • 基类实现较容易一些,基类提供的功能派生类一般稍作改动即可;而接口方法则要实现所有成员。
  • 版本控制:向基类添加新方法后派生类可以直接使用;向接口添加新方法后需要修改源代码并重新编译。

CLR via C#(17)--接口的更多相关文章

  1. [CLR via C#]13. 接口

    一.类和接口继承 在Microsoft.Net Framwork中,有一个名为System.Object的类,它定义了4个公共实例方法:ToString, Equals, GetHashCode和Ge ...

  2. 重温CLR(九) 接口

    对于多继承(multiple inheritance)的概念,许多程序员并不陌生,他是指一个类从两个或多个基类派生的能力.例如,假定TransmitData类的作用是发送数据,ReceiveData类 ...

  3. [CLR via C#]17. 委托

        回调函数是一种非常有用的编程机制,它已经存在很多年了.Microsoft .NET Framework通过委托(delegate)来提供一种回调机制.不同于其他平台(比如非托管C++)的回调机 ...

  4. CLR设计类型之接口

    写在前面的话:             写到这一节的时候,CLR设计类型就已经结束了,因为CLR要求的是有一定基础的人看的,所以我们不是从基础类型以及运算符开始的,文章从一开始就讲的是深入面向对象编程 ...

  5. Java基础教程(17)--接口

      就像类一样,接口也是引用类型.它可以包含常量,方法签名,默认方法,静态方法和嵌套类型.在接口中,只有默认方法和静态方法有方法体.但不同于类,接口无法实例化,它只能被类实现或被其他接口继承. 一.定 ...

  6. 第二十二章 CLR寄宿和AppDomain

    1. 概念解析 CLR Hosting(CLR 宿主):初始启动.Net Application时,Windows进程的执行和初始化跟传统的Win32程序是一样的,执行的还是非托管代码,只不过由于PE ...

  7. 第22章 CLR寄宿和AppDomain

    22.1 CLR寄宿 CLR Hosting(CLR 宿主)的概念:初始启动.Net Application时,Windows进程的执行和初始化跟传统的Win32程序是一样的,执行的还是非托管代码,只 ...

  8. ASP.NET常见面试题及答案(130题)

    1.C#中 property 与 attribute(抽像类)的区别,他们各有什么用处,这种机制的好处在哪里?答:property和attribute汉语都称之为属性.不过property是指类向外提 ...

  9. asp.net面试题汇总

    1.静态成员和非静态成员的区别? 答: 静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对 ...

  10. 100道.net面试题

    简述 private. protected. public. internal 修饰符的访问权限. 答 . private : 私有成员, 在类的内部才可以访问. protected : 保护成员,该 ...

随机推荐

  1. python 字典 注意点

    dict()构造函数直接从键-值对序列创建字典: >>> >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4 ...

  2. ACCESS延时注入

    这也算是个新知识吧.今天遇到个站,实实在在存在注入,但是弄不出字段.本应该可以用便宜注入.但是不知道为什么就是就是弄不出来. 大家如果有兴许可以加学习交流群:281245781 交流一下吧. Payl ...

  3. java代码生成二维码以及解析二维码

    package com.test; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedI ...

  4. linux shell脚本常用语句

    linux shell 指令 诸如-d, -f, -e之类的判断表达式: 文件比较运算符-e filename  如果 filename存在,则为真  [ -e /var/log/syslog ]-d ...

  5. NET程序内存分析工具CLRProfiler的使用(性能测试)

    http://blog.csdn.net/wy3552128/article/details/8158938 大家都知道.net有一套自己的内存(垃圾)回收机制,除非有一些数据(方法)长期占有内存不随 ...

  6. Git的维护(git gc和git fsck)

    原文: http://gitbook.liuhui998.com/4_10.html 一.保证git良好的性能 在大的仓库中, git靠压缩历史信息来节约磁盘和内存空间. 压缩操作并不是自动进行的, ...

  7. SQL合并多行查询到一行

    示例表 tb 数据如下 id value—————1 aa1 bb2 aaa2 bbb2 ccc 第一种 SELECT id, [val]=( SELECT [value] +',' FROM tb ...

  8. POJ 1979

    这是一道比较水的DPS的题目 题意就是求你可以走到的黑色的地板砖的块数,@代表你的起点,也是黑色的地板砖,#代表白色的,则说明你不能走,这就是一个广搜的题目 思路也很简单,如果你周围的那块地板是黑色的 ...

  9. Appium+Robotframework实现Android应用的自动化测试-7:模拟器频繁挂掉的解决方案

    如果测试用例比较多,则当持续运行多个测试用例后,经常会出现模拟器崩溃或者Appium无法连接到该模拟器的情况出现. 经过分析,本人认为这应该是模拟器或者Appium的缺陷造成的,目前并没有直接的解决方 ...

  10. CEF3开发者系列之类和接口

    CEF3基本的框架包含C/C++程 序接口,通过本地库的接口来实现,而这个库则会隔离宿主程序和 Chromium&Webkit的操作细节.它在浏览器控件和宿主程序之间提供紧密的整合,它支持用户 ...