最近在园子里闲逛看到一篇文章“(抽象)类和接口细节分析”,尽管作者很细心很细致。可事实上C#里面的interface没那么简单,interface有着大量不为人知的小秘密的说。

1、值类型也能实现接口。

尽管可能很多人连值类型都没用过,但值类型可以实现接口,是一个非常有用的特性。当值类型转换为接口类型时,会自动装箱成引用类型从而实现多态,但一般用值类型实现接口的老鸟都不会被这些小陷阱所迷惑的。

2、除了接口,没有什么类型可以不实现接口

抽象类可以不实现接口?其实不然,抽象类只能抽象接口的实现,即将实现变为abstract的,但不能不实现接口。也许你会疑惑,abstract实现接口成员和不实现接口成员到底有区别?尽管区别不大,但还是存在的,从理论上来说的话,就是slot上的方法的区别。抽象类用abstract成员实现接口后,子类再override来实现抽象类的abstract成员,这会使得子类的实现是在abstract实现之下而不是直接在接口成员之下。从实际效果上来说,由于抽象类的abstract的实现存在,使得子类中可以选择对抽象类和接口进行分别实现(重新实现接口)。

3、但事实上接口也不能实现接口,只是把多个接口捆绑起来。

一段有趣的代码如下

public interface IA
{
void Test();
} public interface IB : IA { } public interface IC : IA { } public interface ID : IB, IC { }

当实现ID时,等于同时实现ID、IC、IB和IA,但事实上,你只需要实现一个Test方法,也只能实现一个Test方法,也就是IA.Test,IB、IC、ID都是没有Test方法的。

当然,你可以尝试在IB或是其他接口中再放入一个Test,便会产生一些奇妙的事情。

4、同一接口成员在同一类型中只能被实现一次。

显示实现接口已经不是什么秘密了,但很多人却并不知道,如果你显示实现了接口,那么隐式实现就不存在了。这就是接口只能被实现一次:

public interface IA
{
void Test();
} public interface IB
{
void Test();
} public class TestClass : IA, IB
{ public void Test()
{
throw new NotImplementedException();
} void IB.Test()
{
throw new NotImplementedException();
}
}

在这段代码中,第一个Test方法实际上只实现了IA.Test,而如果将第二个Test方法去掉,则第一个方法就会同时实现两个Test,即IA.Test和IB.Test。不妨自己动手去试一下。

5、同一个类型也只能实现同一个接口一次。

其实不论类型的父类重复实现了同一个接口多少次,一个类型只能实现一个接口一次。考虑下面的代码:

public interface ITest
{
void Test();
} public abstract class Test1 : ITest
{
public void Test()
{
throw new NotImplementedException();
}
} public abstract class Test2 : Test1, ITest
{
public new void Test()
{
throw new NotImplementedException();
}
} public abstract class Test3 : Test2, ITest
{
public new void Test()
{
throw new NotImplementedException();
}
}

无论在基类中实现了多少次ITest接口,事实上在ITest3的接口列表中永远只有一个ITest(GetInterfaces),也只能对ITest的每个成员实现一次(隐式或显式)。

6、实现接口的成员实际可见性总是不低于接口可见性。显示实现接口的成员可见性总是等同于接口可见性(因为它们默认都是private的)。

重写基类成员的成员必须有相同的可见性,接口则不必,隐式实现总是要求成员必须为public。同时,一个类型可以实现可见性比自己高或低的接口,但不能继承可见性比自己低的基类。

因为能访问到接口的类型的地方一定能访问到接口的实现成员,所以实现接口的成员的实际可见性总不低于接口。

一个很常见的手法,一个可见性较低的类型通过可见性高的接口来暴露自己的成员,事实几乎所有的枚举器(IEnumerator的实例)都是private的类型,透过接口来暴露功能。

当然,你也可以设计一个internal的接口,然后让某个类型去“显示实现”,这个时候实现接口的成员的“实际”可见性将跟随接口变为internal。

由于隐式实现接口要求成员必须是public的,如果要用可见性较低的接口来制约成员可见性就只能用显式实现接口成员。也许有人会很奇怪我干嘛降级成员的可见性?因为有时候可见性高了并不是什么好事,它会破坏组件(不是类型)的封装。当然更多的时候,我们只是需要一个手段来统一设置某些成员的可见性。

不过,我们也能想出更多非常好玩的玩法:

public abstract class Test
{
protected interface ITest
{
void Test();
} public class Nested : ITest
{ void ITest.Test()
{
throw new NotImplementedException();
}
}
}

这也是显示实现接口特性除了解决名称和冲突问题之外最大的用处。

C#中的interface没那么简单的更多相关文章

  1. 【转载 来自sdnlab】 开放网络没那么简单

    链接:开放网络没那么简单 本文是云杉网络工程师张攀对当前开源网络技术现状的一些思考和探索. 开放网元.释放数据的价值 从2012年开始至今,网络行业明显是O字辈的天下.所有我接触过了解过的组织和项目, ...

  2. /dev/mem可没那么简单

    这几天研究了下/dev/mem.发现功能非常奇妙,通过mmap能够将物理地址映射到用户空间的虚拟地址上.在用户空间完毕对设备寄存器的操作,于是上网搜了一些/dev/mem的资料. 网上的说法也非常统一 ...

  3. /dev/mem可没那么简单【转】

    转自:http://blog.csdn.net/skyflying2012/article/details/47611399 这几天研究了下/dev/mem,发现功能很神奇,通过mmap可以将物理地址 ...

  4. iOS中js与objective-c的简单交互

    1.首先是objective-c调用js中的代码,可以用UIWebview中的一个方法 stringByEvaluatingJavaScriptFromString:后面接的是js中的方法名.这个函数 ...

  5. python中线程和进程的简单了解

    python中线程和进程的简单了解   一.操作系统.应用程序 1.硬件:硬盘.cpu.主板.显卡........ 2.装系统(本身也是一个软件): 系统就是一个由程序员写出来的软件,该软件用于控制计 ...

  6. 安全开发Java:日志注入,并没那么简单

    摘要:当web工程比较大,历史代码较多时, 应当使用log4j2框架的能力来修改日志注入问题,而不是按照有些博文里写的逐个进化参数的方式. 案例故事 某个新系统上线了,小A在其中开发了个简单的登录模块 ...

  7. iOS中,在类的源文件(.m)中,@interface部分的作用?

      此@interface部分为类扩展(extension). 其被设计出来就是为了解决两个问题的 其一,定义类私有方法的地方. 其二,实现public readonly,private readwr ...

  8. Android中NDK的搭建及简单使用 Android.mk相关介绍 JNI的使用

    Android中NDK的搭建及简单使用: 使用NDK,简述其重要步骤:.搭建NDK环境(作用:用于自动生成jni下的.c对应的so文件)---到Android NDK官网或Android官网下载ndk ...

  9. OC中的@interface和java中的区别以及 @implementation @protocol

      java 在java中的interface是‘接口’的意思,而java的类声明用class,即接口用interface声明,类是用class声明,是两个独立的部分. 只有在类声明要实现某个接口时, ...

随机推荐

  1. Altium Designer的pcb上添加文字说明

  2. 微信浏览器跳转外部浏览器 app下载

    这个是摘抄的,具体抄的哪里我忘记了,作为记录 2019年5月14日 现在这个好像也不好用了,微信又提示建议下载qq浏览器什么的,显示一个红色感叹号,让用户产生怀疑,很鄙视tx error_report ...

  3. 10.6 android输入系统_Dispatcher线程_总体框架

    图解Android - Android GUI 系统 (5) - Android的Event Input System - 漫天尘沙 - 博客园.htm // 关注里面的Dispatcher处理流程h ...

  4. ORA-00119: invalid specification for system parameter LOCAL_LISTENER;

    错误提示内容及上下文环境: SQL> grant sysdba to weng;grant sysdba to weng*第 1 行出现错误:ORA-01034: ORACLE not avai ...

  5. MHA 一主两从搭建-脚本VIP-自动切换

    环境介绍:主机名 IP MHA角色 MySQL角色node1 192.168.56.26 Node MySQL Master node2 192.168.56.27 Node MySQL Master ...

  6. css3-9 css中的浮动怎么使用

    css3-9 css中的浮动怎么使用 一.总结 一句话总结:用来做一般的行效果,比如说手机左右分布的头部导航栏.浮动的东西放到一个div中去,里面的内容根据需求左浮动或者右浮动,然后记得加上清除浮动. ...

  7. 手动打war包进行部署测试

    有的时候项目跑不起来但是又不知道tomcat问题还是其他问题,往往新建个项目,打成war进行部署.今天找到个好方法,手动打成war,然后进行部署测试. image.png image.png 创建一个 ...

  8. 用SQL找出前N名

    业务系统中常常会有排名的需求,考试和比赛中则更普遍了.Excel 中也有个 Rank 函数供排名之用,数据库中更不例外了. 如果须要找出工资最高的前三个员工工资(及其员工号). 只是."前三 ...

  9. Android中蓝牙的基本使用----BluetoothAdapter类简介

    天气逐渐热了,自己也越来越懒了,虽然看着了很多东西,解决了很多问题,有些收获却不想写着.主要有一下两方面原因: 第一.以前写的一些关于Android知识的Blog,都是在学习过程中发现网络上没有相关知 ...

  10. MONyog使用图解(一)-数据库性能监控工具

    原文:MONyog使用图解(一)-数据库性能监控工具 一.安装步骤 较为简单,网上可以搜索到,此处不做详细说明. 二.使用图解 此处介绍监控数据库连接量.并发量.吞吐量.响应时间等功能 1.设置连接需 ...