C#学习笔记(15)——c#接口

说明(2017-7-17 21:57:26):

原文:http://www.cnblogs.com/jiajiayuan/archive/2011/09/16/2178462.html

本文意在巩固基础知识,并不是对其进行深入剖析,还望理解。
本文为原创文,难免会有一些小得瑕疵,敬请谅解。
所有示例均是博主测试过的,如有转载请标明出处,谢谢。
在编程中,我们经常会用到接口,那什么是接口呢?
接口描述的是可属于任何类或结构的一组相关功能,所以实现接口的类或结构必须实现接口定义中指定的接口成员。
接口使用interface 关键字进行定义,可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。
接口的特性:
1.接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:
显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。
隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的
2.接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员。
3.接口成员是自动公开的,且不能包含任何访问修饰符。
4.接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类。
为什么不能指定接口中方法的修饰符? 
接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。它们默认为公有方法。

interface IProgram    {        void Fun();    }    class Program:IProgram    {         //显式实现接口成员        void IProgram.Fun()        {            Console.WriteLine("I am Fun.");        }        staticvoid Main(string[] args)        {            IProgram p =new Program();  //声明一个接口实例,但不是对接口进行实例化            p.Fun();            Console.Read();        }    }

上面提到,实现接口可以显式实现和隐式实现,那么这两种实现到底有什么优缺点呢?
一般情况,当类或者结构要实现的是单个接口,可以使用隐式实现。
如果类或者结构继承了多个接口且接口中具有相同名称成员时,就要用到显式实现,当显式实现方式存在时,隐式实现方式就失效了。

interface IProgram    {        void Fun();    }    interface IAProgram    {        void Fun();    }    class Program : IProgram, IAProgram    {        void IProgram.Fun()  //显式实现接口IProgram        {            Console.WriteLine("I am IProgram Fun.");        }        void IAProgram.Fun()  //显式实现接口IAProgram        {            Console.WriteLine("I am IAProgram Fun.");        }        //public void Fun()   //隐式实现接口        //{        //    Console.WriteLine("I am Program Fun.");        //}        staticvoid Main(string[] args)        {            //IProgram p = new Program();            //p.Fun();            //IAProgram ap = new Program();            //ap.Fun();            Program pro =new Program();            ((IProgram)pro).Fun();            ((IAProgram)pro).Fun();            Console.Read();        }    }

结果为:I am IProgram Fun.
           I am IAProgram Fun.
接口的继承:
接口继承和类继承不同:首先,类继承不仅是说明继承,而且也是实现继承;而接口继承只是说明继承。
也就是说,派生类可以继承基类的方法实现,而派生的接口只继承了父接口的成员方法说明,而没有继承父接口的实现,
其次,C#中类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口。
接口可以从零或多个接口中继承。从多个接口中继承时,用":"后跟被继承的接口名字,多个接口名之间用","分割。
被继承的接口应该是可以访问得到的,比如从private 类型或internal 类型的接口中继承就是不允许的。
接口不允许直接或间接地从自身继承。和类的继承相似,接口的继承也形成接口之间的层次结构。

    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();        }    }

接口的覆盖:
由于接口的实现没有方法体,抽象方法也没有方法体,那么当我们在接口的实现方法里调用抽象方法时,会如何执行呢?

    interface IProgram    {        void Fun();    }    abstractclass AProgram : IProgram    {        publicabstractvoid AFun();        void IProgram.Fun()        {            AFun();        }    }    class Program:AProgram    {        publicoverridevoid AFun()        {            Console.WriteLine("I am AProgram.");        }        staticvoid Main(string[] args)        {            IProgram pro =new Program();            pro.Fun();            Console.Read();        }    }//结果:I am Aprogram.

通过断点,可以看到,当执行pro.Fun();时,首先会跳到接口的实现方法里,然后去调用抽象函数的实现方法,当抽象函数的方法实现后,再回到接口的实现方法,直到执行完成。
当我们在实现接口的方法里调用虚函数呢?

    interface IProgram    {        void Fun();    }    class AProgram : IProgram    {        publicvirtualvoid AFun()    //注意这里是虚函数        {            Console.WriteLine("I am virtual AFun.");        }        void IProgram.Fun()        {            AFun();        }    }    class Program:AProgram    {        publicoverridevoid AFun()  //这里是Override重写        {            Console.WriteLine("I am override AFun.");        }        staticvoid Main(string[] args)        {            IProgram pro =new Program();            pro.Fun();            Console.Read();        }    }

这时,我们发现,执行的顺序和上一个例子是相同的。所以结果为:I am override AFun.
由此,我们可以继续联想,当我们把override关键字,换成new呢?是不是也是同样的结果,还是和我们以前讲的例子一样,是隐藏呢?
我们把上面的例子进行改进:

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

结果为:I am virtual AFun.
           I am new AFun.
由于前面已经讲过了,这里不在对此进行分析,由此我们可知使用New关键字是对其进行隐藏,当对接口实现的方法里调用的是虚方法时,和类的执行过程是一样的。
接口和抽象类的区别。

接口用于规范,抽象类用于共性。
接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。
抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。
抽象类可以提供某些方法的部分实现,接口不可以。
抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。 
在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。
接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。
此外接口不能包含字段、构造函数、析构函数、静态成员或常量。 
C#中的接口和类有什么异同。 
异: 
不能直接实例化接口。 
接口不包含方法的实现。 
接口可以实现多继承,而类只能是单继承。 
类定义可在不同的源文件之间进行拆分。 
同: 
接口、类和结构可从多个接口继承。 
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。 
接口可以包含事件、索引器、方法和属性。 
一个类可以实现多个接口。

时间: 2024-10-11 05:32:47

C#学习笔记(15)——c#接口的相关文章

我的java学习笔记(15)关于接口

1.接口技术主要用来描述具有什么功能,而并不给出每个功能的具体实现. 2.一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象. 3.在java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类的需求要遵从接口描述的统一格式进行定义. 4.接口中的所有方法自动的属于public. 5.接口决不能含有实例域,也不能在接口中实现方法. 6.提供实例域和方法实现的任务应该由实现接口的那个类来完成. 7.可以将接口看成是没有实例域的抽象类.但是这两个概念还是有区别的.

Perl语言学习笔记 15 智能匹配与give-when结构

1.智能匹配操作符 替代绑定操作符: 在哈希中查找某一个键: 比较两个数组是否完全相同: 查找列表中是否存在某个元素: 智能匹配操作符与顺序无关,~~ 左右元素可以互换 2.智能操作符优先级 3.given语句 相当于c语言的switch语句 4.given可以测试多个条件,在default前用break,否则会导致default一直执行 5.笨拙匹配(正则表达式方式) 6.多个项目的when匹配 可以在语句中间加上其他语句: Perl语言学习笔记 15 智能匹配与give-when结构,布布扣

Swift学习笔记(15)--下标脚本(Subscripts)

下标脚本可以定义在类(Class).结构体(structure)和枚举(enumeration)这些目标中,使用中类似数组或者字典的用法 1.定义 定义下标脚本使用subscript关键字,语法: subscript(index: Int) -> Int { get { // 返回与入参匹配的Int类型的值 } set(newValue) { // 执行赋值操作 } } 注:newValue的类型必须和下标脚本定义的返回类型相同.与计算型属性相同的是set的入参声明newValue就算不写,在s

python基础教程_学习笔记15:标准库:一些最爱——fileinput

标准库:一些最爱 fileinput 重要的函数 函数 描述 input([files[,inplace[,backup]]) 便于遍历多个输入流中的行 filename() 返回当前文件的名称 lineno() 返回当前(累计)的名称 filelineno() 返回当前文件的行数 isfirstline() 检查当前行是否是文件的第一行 isstdin() 检查最后一行是否来自sys.stdin nextfile() 关闭当前文件,移动到下一个文件 close() 关闭序列 fileinput

springmvc学习笔记(15)-数据回显

springmvc学习笔记(15)-数据回显 springmvc学习笔记15-数据回显 pojo数据回显方法 简单类型数据回显 本文介绍springmvc中数据回显的几种实现方法 数据回显:提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面. pojo数据回显方法 1.springmvc默认对pojo数据进行回显. pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写) 使用@ModelAttribute

Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法

Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法 Summary的用法和Group一样简单,分为两步: 启用Summary功能 在Feature标签内,添加如下代码: <ext:Summary runat="server"></ext:Summary> 使用汇总列 然后我们需要在ColumnModel中使用SummaryColumn: <ext:SummaryColumn runat="server&qu

[原创]java WEB学习笔记15:域对象的属性操作(pageContext,request,session,application) 及 请求的重定向和转发

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

Flask框架学习笔记(API接口管理平台 V2.0)

博主今天把API接口管理平台发布到github了,这次是更新一些功能 如支持本地数据库sqlite3.优化了数据结构 技术方面跟之前V1.0相同,只增加生产本地数据:但是为了支持层级的参数,修改了数据结构,下面是新的model.py 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 from app import db 5 6 7 class User(db.Model): 8 user_id = db.Column(db.Integer

【学习笔记】C# 接口

使用interface关键字定义接口 接口定义一组成员但不直接实现它们 实现接口 实现接口的任何类都必须实现其所有的成员方法 接口不能直接实例化 接口可以包含方法和属性声明,不能包含字段 接口中所有属性和方法默认为public 一个子类可以继承一个父类的同时,实现多个接口 1 using System; 2 3 namespace InterfaceDemo 4 { 5 //食物接口 6 public interface Food 7 { 8 //在接口中定义属性,属性也不能实现 9 float

js-权威指南学习笔记15

第十五章 脚本化文档 1.文档对象模型DOM是表示和操作HTML和XML文档内容的基础API. 2.Document.Element.Text是Node的子类. 3.查询文档的一个或多个元素有如下方法:用指定的id属性.用指定的name属性.用指定的标签名字.用指定的css类.匹配指定的css选择器. 4.HTML的name属性最初打算为表单元素分配名字,在表单数据提交到服务器时使用该属性的值. 5.name属性只在少数HTML元素中有效,包括表单.表单元素.iframe和img元素. 6.ge