CLR设计类型之接口
写在前面的话:
写到这一节的时候,CLR设计类型就已经结束了,因为CLR要求的是有一定基础的人看的,所以我们不是从基础类型以及运算符开始的,文章从一开始就讲的是深入面向对象编程,研究C#程序的设计模式。C#面向对象编程有三个特点:封装,继承,多态。接口的实现就是实现继承
其实在开始之前说一下这两天发生的事情,前几天维护项目代码时,虽然是自己写得但是由于逻辑判断比较多,有些变量名起的也不是很有意义,在看的时候就完全忘记当初为啥要写成这样了,也是有点汗颜,所以最近就把代码整洁之道也放在了看书的目录上,今后的示例代码也会符合代码整洁之道上的一些要求去写。而不是用无意义的a,b,c去做为变量名。
接口定义:
那么接口要做的事,也是让代码更加简洁的事情,接口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分。接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。
说了这么多,那么我们用接口实现一个计算器的例子,通过这个例子来说明接口到底是如何定义,如何使用的。先看接口的定义:
interface ICalculator {
//通常接口命令以 I 字母开头,ICalculator 中文意思就是计算器接口
//这个接口规定了一个计算器要有基本的加减乘除运算方法
//加法
int Add(int x,int y);
//减法
int Reduce(int x, int y);
//乘法
int Ride(int x, int y);
//除法
int Except(int x, int y);
}
接口实现:
上面的代码很简单吧,在接口中不能声明静态方法,接口中的方法不能用可见性修饰符修饰,在来看这句话:接口定义了所有类继承接口时应遵循的语法合同,也就是接口先规定好了我要实现那些方法和行为,继承我的要实现(重写)我的所有方法,并且返回值要和我相同,参数也要和我相同。否则就是违反了合同,语法就会报出错误。有了合同,类现在就像是一个建筑包工头,我只需要按照你的约定做,你让我盖十层楼,我就盖十层楼。继承接口类如下:
public class Calculator : ICalculator
{
//:表示继承了计算机接口
//实现接口中的加法
public int Add(int x, int y) {
int sum = x + y;
return sum;
}
//实现接口中的减法
public int Reduce(int x, int y)
{
int sum = x - y;
return sum;
}
//实现接口中的乘法
public int Ride(int x, int y)
{
int sum = x * y;
return sum;
}
//实现接口中的除法
public int Except(int x, int y)
{
int sum = x / y;
return sum;
}
}
接口调用:
继承类必须实现接口中的所有方法,并且不能静态类继承接口,这里实现了接口中得所有方法,继续用上一个例子,接口好比是一个承包方:会告诉你我要什么样的房子,房子的颜色和大小,继承类就是施工方,按照承包方的要求去盖房子,知道了房子大小就开始计算要买多少砖瓦水泥。那么实现了接口的类如何调用实现呢?和正常的类一样调用和实现:
static void Main(string[] args)
{
//实例化一个计算器
Calculator calculator1 = new Calculator();
//输出计算器的实现 输出结果为3
Console.WriteLine(calculator1.Reduce(, ));
}
这就是一个最简单的接口调用和实现。看了这么多,你可能觉得使用接口不是更加麻烦了么?如果从基类中继承不是更加简单?这样还需要定义接口,并且接口中所有成员都必须实现其方法。表明上来看是这样的,那么所有东西都有其使用的场景,接口的出生也不是为了简单类而出生。C#和CLR所支持的泛型接口为开发人员提供了许多非常出色的功能,接下来我们讨论一下泛型接口提供的一些好处
泛型接口
首先泛型接口提供了出色的编译时类型安全性,有的接口在定义的方法使用了object参数或object返回类型,在代码调用这些接口方法时,可传递任何类型的实例应用,但这通常不是我们期望的,并且使用非泛型还会造成装箱拆箱操作,今天列举C#中另外一个泛型接口IComparable,
public interface IComparable<in T>
{
//
// 摘要:
// 比较当前对象和同一类型的另一对象。
//
// 参数:
// other:
// 与此对象进行比较的对象。
//
// 返回结果:
// 一个值,指示要比较的对象的相对顺序。返回值的含义如下:值含义小于零此对象小于 other 参数。零此对象等于 other。大于零此对象大于 other。
int CompareTo(T other);
}
这是进行大小比较的接口,接受的参数是泛型,并且泛型参数支持协变和逆变,更大程度的支持参数的灵活性,他展示了泛型接口的另外一个好处,类可以实现一个接口若干次,只要每次使用不同的类型参数,示例:
public sealed class Comparable:IComparable<int>,IComparable<string>
{
private int m_val=;
//方法实现了IComparable<string>的CompareTo方法
public int CompareTo(string str)
{
return m_val.CompareTo(Convert.ToInt32(str));
}
//方法实现了IComparable<string>的CompareTo方法
public int CompareTo(int number)
{
return m_val.CompareTo(number);
}
}
需要说明的是,上面的代码最终在return m_val.CompareTo(Convert.ToInt32(str));这里实际调用的元数据int的CompareTo方法,因此虽然可以接收不同类型参数,但在比较的时候还是要对泛型参数进行int转化,才可以实现int的CompareTo方法。
泛型接口约束
泛型接口还可以对自身进行约束,也称作接口约束,接口约束可以将泛型类型参数约束为多个接口,这样一来,传递的参数类型必须全部接口约束。初读这段话是不是很晕?什么是将泛型类型参数约束为多个接口?为什么约束过后,传递的参数类型必须实现全部约束?全部约束指的是哪一些约束?
public static class SomeType {
private static void Test() {
int x = ;
Guid g = new Guid();
//可以通过 因为int继承了IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
M(x);
//编译不能通过,因为GUID没有继承IConvertible
//public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid>
M(g);
}
//M的类型参数T被约束为只支持同时实现了
//IComparable和IConvertible接口的类型
private static int M<T>(T t) where T : IComparable, IConvertible {
return ;
}
}
上面的方法,就是将参数约束了指定的接口,并且只有实现被约束的接口才能通过编译,否则就会失败。这就是接口的泛型约束。
总结:类还是接口?
首先类只能继承一个实现,而接口可以继承多个,如果多种对象类型都能做某事,就为它创建接口。
如果是简单的类型,那么就使用基类,基类实现了大量的功能,并且不用实现所有成员
CLR设计类型之接口的更多相关文章
- CLR - 设计类型
前言 好记性不如烂“笔头”系列... 目录 类型基础 基元类型.引用类型和值类型 类型与成员 常量与字段 方法 类型基础 “运行时”要求每个类型最终都从System.Object 类型派生. 由于所有 ...
- [CLR via C#]13. 接口
一.类和接口继承 在Microsoft.Net Framwork中,有一个名为System.Object的类,它定义了4个公共实例方法:ToString, Equals, GetHashCode和Ge ...
- 重温CLR(九) 接口
对于多继承(multiple inheritance)的概念,许多程序员并不陌生,他是指一个类从两个或多个基类派生的能力.例如,假定TransmitData类的作用是发送数据,ReceiveData类 ...
- 【转】App架构设计经验谈:接口的设计
App架构设计经验谈:接口的设计 App与服务器的通信接口如何设计得好,需要考虑的地方挺多的,在此根据我的一些经验做一些总结分享,旨在抛砖引玉. 安全机制的设计 现在,大部分App的接口都采用REST ...
- 微信小程序的Web API接口设计及常见接口实现
微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,通过小程序的请求Web API 平台获取JSON数据后,可以在小程序界面上进行数据的动态展示.在数据的关键 一环中,我们 ...
- 编写高质量代码改善C#程序的157个建议——建议97:优先考虑将基类型或接口作为参数传递
建议97:优先考虑将基类型或接口作为参数传递 除了公开及类型或接口外,方法的参数也应该考虑基类型或接口. 以Enumerable类型为例,它的成员方法中只要涉及需要操作集合对象的地方,都要使用IEnu ...
- 编写高质量代码改善C#程序的157个建议——建议96:成员应优先考虑公开基类型或接口
建议96:成员应优先考虑公开基类型或接口 类型成员如果优先考虑公开及类型或接口,那么会让类型支持更多的应用场合. FCL中最典型的例子是集合的功能操作.集合根据功能划分有多种类型,比如List< ...
- Go_笔试题记录-指针与值类型实现接口的区别
1.如果Add函数的调用代码为: func main() { var a Integer = 1 var b Integer = 2 var i interface{} = &a sum := ...
- 使用suds模块进行封装,处理webservice类型的接口
import json from suds.client import Client class HandleWebservice: ''' 定义一个webservice类型的接口处理类 ''' de ...
随机推荐
- HDU2282 Chocolate KM算法
第一次做这样的题,其中有几个细节是反复思考反复调试,最后一A的,ORZ,又加深了对KM算法的理解.能不参考网上的题解,而是平静下来思考,参透,最后敢于尝试.....真的很重要,以后遇到才会有更深的印象 ...
- GBK和UTF8有什么区别
GBK编码:是指中国的中文字符,其它它包含了简体中文与繁体中文字符,另外还有一种字符“gb2312”,这种字符仅能存储简体中文字符. UTF-8编码:它是一种全国家通过的一种编码,如果你的网站涉及到多 ...
- 线性布局(LinearLayout)
线性布局(LinearLayout) 备注 match_parent填充布局单元内尽可能多的空间 wrap_content完整显示控件内容 orientation有两个值,horizontal水平显示 ...
- Python通过future处理并发
future初识 通过下面脚本来对future进行一个初步了解:例子1:普通通过循环的方式 import os import time import sys import requests POP20 ...
- Arrays.asList () 不可添加或删除元素的原因
Java中奖数组转换为List<T>容器有一个很方便的方法 Arrays.asList(T ... a),我通过此方法给容器进行了赋值操作,接着对其进行 添加元素,却发现会抛出一个(jav ...
- 搭建Hadoop平台(新手入门)
刚刚大学毕业,接触大数据有一年的时间了,把自己的一些学习笔记分享给大家,希望同热爱大数据的伙伴们一起学习,成长! 资料准备: Hadoop-2.7.1下载:http://pan.baidu.com/s ...
- Install Ubuntu On Windows10(win10上安装linux系统)
一.准备: 硬件:U盘 软件:ultraiso.Ubuntu镜像文件 二.安装linux: 1.Ubuntu官网(http://www.ubuntu.org.cn/download/alternati ...
- 窗口迅速关闭的解决办法/scanf/if/for/break
break if的格式 if(a>b) { printf("max=%d\n",a); } else printf("max=%d\n",b); scan ...
- 基于nginx搭建简易的基于wcf集群的复杂均衡
很多情况下基于wcf的复杂均衡都首选zookeeper,这样可以拥有更好的控制粒度,但zk对C# 不大友好,实现起来相对来说比较麻烦,实际情况下,如果 你的负载机制粒度很粗糙的话,优先使用nginx就 ...
- (转)关于Tomcat的点点滴滴(体系架构、处理http请求的过程、安装和配置、目录结构、设置压缩和对中文文件名的支持、以及Catalina这个名字的由来……等)
转自:http://itfish.net/article/41668.html 总结Tomcat的体系架构.处理http请求的过程.安装和配置.目录结构.设置压缩和对中文文件名的支持.以及Cata ...