基础拾遗------接口详解

  接口定义了所有类继承接口时应遵循的契约。接口定义了 "要什么" ,派生类定义了 "怎么给" 。

 引用CLR VIA C#(类和接口继承)

  在Microsoft.Net Framwork中,有一个名为System.Object的类,它定义了4个公共实例方法:ToString, Equals, GetHashCode和GetType。该类是其他所有类的根或者说最终基类。换言之,所有类都继承了Object的4个实例方法。这还意味着能操作 Object类的实例的代码实际能操作任何类的实例。

  在CLR中,任何类都肯定从一个类也只能从一个类(而且只能从Objetc派生的类)派生的。这个类称为基类。基类提供了一组方法签名和这些方法的实现。你定义的新类可在将来由其它开发人员用作基类——所有方法签名和方法实现都会由新的派生类继承。

  CLR允许开发人员定义接口,它实际只是对一组方法签名进行了统一的命名。这些方法没有提供任何实现。类通过指定接口与名称来实现这个接口,它必须显式提供接口方法的实现,否则CLR会认为此类型定义无效。

类继承有一个重要特点,凡是能使用基类型实例的地方,都能使用派生类型的实例。类似的,凡是能使用具有接口类型实例的地方,都能使用实现了这个接口的一个类型的实例。

1.接口的特性

  1.1.接口是一个引用类型,通过接口可以实现多重继承。

  1.2.接口成员是自动公开的(public),且不能包含任何访问修饰符(public、protected、internal、private),否则 编译器会报错。

  1.3.接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:

   当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。

    当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的。

  1.4.接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员,只能包含方法、属性、事件、索引等成员。

  1.5.接口成员不能有static、abstract、override、virtual修饰符,使用new修饰符不会报错,但会给出警告说不需要关键字new。

  1.6.在声明接口成员的时候,不准为接口成员编写具体的可执行代码,也就是说,只要在对接口进行声明时指明接口的成员名称和参数就可以了。

2.接口与抽象类

2.1下面让我们来对接口与抽象类做个对比。如有不同意见欢迎讨论。

interface

abstract class

实例化

不可以

不可以

派生类实现

必须实现所有契约

实现没实现的方法

继承

接口支持多继承

必须抽象类不能实现多继承

抽象

接口只能定义抽象规则

抽象类既可以定义规则,还可能提供已实现的成员。但不能使用new关键字,也不能被密封,原因是抽象类不能被实例化

概念

接口是一组行为规范

抽象类是一个不完全的类

回调

接口可以用于支持回调

抽象类不能实现回调,因为继承不支持

成员

接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法

抽象类可以定义字段、属性、包含有实现的方法

数据类型

接口可以作用于值类型和引用类型。例如,Struct就可以继承接口,而不能继承类

抽象类只能作用于引用类型

构造方法

没有构造方法

有构造方法

静态方法

没有静态方法(默认public static final类型)

包含静态方法

修饰符

默认public没有其他修饰符。

可以是public,protected

 2.2.抽象类和接口的使用:

2.2.1. 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本;

2.2.2.如果创建的功能将在大范围的全异对象间使用,则使用接口。如果要设计小而简练的功能块,则使用接口;

2.2.3.如果要设计大的功能单元,则使用抽象类.如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类; 

2.2.4.抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。

3.接口声明

  3.1.接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的;

  3.2.根据约定,接口类型名称要以大写字母I开头;

public interface ITransactions
{
   // 接口成员
   void showTransaction();
   double getAmount();
}

注:3.3.对CLR而言,定义接口就像定义类型,也就是说,CLR会为接口类型对象定义一个内部数据结构,同时可用反射机制来查询接口类型的功能。

  3.4.为什么不能指定接口中方法的修饰符?

 接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。它们默认为公有方法。

4.接口的实现

 C#中的接口提供了一种实现运行时的多态。

 4.1.案例

using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InterfaceApplication
{

   public interface ITransactions
   {
      // 接口成员
      void showTransaction();
      double getAmount();
   }
   public class Transaction : ITransactions
   {
      private string tCode;
      private string date;
      private double amount;
      public Transaction()
      {
         tCode = " ";
         date = " ";
         amount = 0.0;
      }
      public Transaction(string c, string d, double a)
      {
         tCode = c;
         date = d;
         amount = a;
      }
      public double getAmount()
      {
         return amount;
      }
      public void showTransaction()
      {
         Console.WriteLine("Transaction: {0}", tCode);
         Console.WriteLine("Date: {0}", date);
         Console.WriteLine("Amount: {0}", getAmount());

      }

   }
   class Tester
   {
      static void Main(string[] args)
      {
         Transaction t1 = new Transaction("001", "8/10/2012", 78900.00);
         Transaction t2 = new Transaction("002", "9/10/2012", 451900.00);
         t1.showTransaction();
         t2.showTransaction();
         Console.ReadKey();
      }
   }
}

  当上面的代码被编译和执行时,它会产生下列结果:

Transaction: 001
Date: 8/10/2012
Amount: 78900
Transaction: 002
Date: 9/10/2012
Amount: 451900

  4.2接口的隐式实现与显示实现

  4.2.1隐式实现

  interface IAnimal
    {
       void Dog();
    }
    class Animal:IAnimal
    {
      public void Dog()
      {
       //#
      }
     }
    //通过类调用
    Animal animal = new Animal();
    animal.Dog();
    //或者通过接口调用
    IAnimal animal = new Animal();
    animal.Dog();

以上:类与接口都能调用的为隐式实现。

  4.2.2.显示实现

interface IAnimal
  {
    void Dog();
  }
  class Animal:IAnimal
  {
    void IAnimal.Dog()
    {
      //#
    }
  }
IAnimal animal = new Animal();
animal.Dog();
Animal animal = new Animal();
(animal as IAnimal).Dog();

以上:用类的方法调用需要强制转换的实现为显示实现。

是不是感觉显示实现多余项目中也从来不曾遇到过???

  4.3.接口隐式实现,显示实现的场景

    4.3.1.当类实现一个接口时,通常使用隐式接口实现,这样可以方便的访问接口方法和类自身具有的方法和属性。

    4.3.2.当类实现多个接口时,并且接口中包含相同的方法签名,此时使用显式接口实现。即使没有相同的方法签名,仍推荐使用显式接口,因为可以标识出哪个方法属于哪个接口。

    4.3.3隐式接口实现,类和接口都可访问接口中方法。显式接口实现,只能通过接口访问。

5.接口的继承

5.1.接口继承和类继承不同:

    5.1.1.类继承不仅是说明继承,而且也是实现继承;而接口继承只是说明继承。

    5.1.2.C#中类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口(用","分割)。

5.2.接口的继承也形成接口之间的层次结构

 interface IProgram
    {
        void Fun();
    }
    interface IAProgram:IProgram
    {
        
    }
    class Program :  IAProgram
    {
        void IProgram.Fun()
        {
            Console.WriteLine("I am IProgram Fun.");
        }
        staticvoid Main(string[] args)
        {
            Program pro =new Program();
            ((IAProgram)pro).Fun();
            Console.Read();
        }
    }

6.接口的覆盖

  通过接口,可以指定组件必须实现的方法,但不实际指定如何实现方法。抽象类可以创建行为的定义,同时提供用于继承类的一些公共实现。对于在组件中实现多态行为,接口和抽象类都是很有用的工具。

  现在我们把一个抽象类被允许把接口方法映射到抽象方法中:

interface ICompute
    {
        void Add();
        void Subtract();
    }

abstract class Compute  : ICompute
{
    void ICompute.Add() { ComputeAdd(); }
    void ICompute.Subtract() { ComputeSubtract(); }
    protected abstract void ComputeAdd();
    protected abstract void ComputeSubtract();
}

  这里,从Compute派生的非抽象类要覆盖ComputeAdd和 ComputeSubtract, 因此提供了ICompute的实际实现程序。

7.接口泛型

 不多说:基础拾忆------泛型详解

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏blackheart的专栏

[C#1] 3-基元类型、引用类型和值类型、装箱拆箱

1.基元类型 编译器直接支持的数据类型成为基元类型。基元类型与FCL中的类型有直接的映射关系[int=Int32],这样我们可以简化的方式书写代码,并且编译后的...

1775
来自专栏nummy

ECMAScript 6 特性ECMAScript 6 特性

ECMAScript 6,也被称做ECMAScript 2015,是ECMAScript标准的下一个版本。这个标准预计将于2015年6月被正式批准。ES6是这门...

491
来自专栏我爱编程

Day12面向对象高级编程3/3

使用元类 type() class Hello(object): def hello(self,name='World!'): prin...

3277
来自专栏java初学

final关键字

34812
来自专栏Ryan Miao

java枚举类型学习

用的不多,但用的时候仅仅简单的使用,不太明白原理,今天就系统的学一下枚举。参考:java编程思想。 Update: 枚举可以当做数据字典来存储,通常只要一个字段...

2679
来自专栏.NET技术

C#系列之值类型和引用类型

    这几天一直在思考这章讨论什么, 在上一章讨论string的时候牵涉到引用类型,那么我们这一章讨论讨论一下,值类型和引用类型。

755
来自专栏个人随笔

ADO.NET查询和操作数据库

stringbuilder 类 stringbuilder类:用来定义可变字符串 stringbulider Append(string value)   在结...

3145
来自专栏技术/开源

30分钟?不需要,轻松读懂IL

先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用。到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点...

1837
来自专栏带你撸出一手好代码

不使用回调函数的ajax请求实现(async和await简化回调函数嵌套)

在常规的服务器端程序设计中, 比如说爬虫程序, 发送http请求的过程会使整个执行过程阻塞,直到http请求响应完成代码才会继续执行, 以php为例子 ? 当...

3005
来自专栏个人随笔

那些年~~~我们的C#笔试内测题目

《深入.NET平台和C#编程》内部测试题-笔试试卷 一 选择题 1) 以下关于序列化和反序列化的描述错误的是( C)。 a) 序列化是将对象的状态存储到特定存储...

30211

扫描关注云+社区