《C#图解教程》读书笔记之六:接口和转换
本篇已收录至《C#图解教程》读书笔记目录贴,点击访问该目录可获取更多内容。
一、接口那点事儿
(1)什么是接口?
一组函数成员而未实现的引用类型。只有类和结构能实现接口。
(2)从IComparable接口看接口实例:
假设有如下一段代码,它使用Array类的一个静态方法Sort对一个未排序的int类型数组进行排序,并输出排序后的结果。
using System; class Program
{
static void Main()
{
var myInt = new[] { , , , , }; // Create an array of ints. Array.Sort( myInt ); // Sort elements by magnitude. foreach ( var i in myInt ) // Print them out.
Console.Write( "{0} ", i );
}
}
Sort方法在int类型数组的排序工作上做的很好,但是如果我们尝试在自定义的类上使用就会发生异常,例如下面的MyClass类。
class MyClass
{
public int TheValue;
}
Sort为何不能对MyClass进行排序,原因在于:它不知道如何比较自定义对象及如何进行排序。Array类的Sort方法其实依赖于一个IComparable的接口,它声明在BCL中,包含唯一的CompareTo方法。它接收一个object类型的参数,可以匹配任何引用类型。
public interface IComparable
{
int CompareTo(object obj);
}
这下,我们知道了int类型默认实现了IComparable接口,而我们的MyClass则没有。因此,我们需要将MyClass实现这个IComparable接口。
class MyClass : IComparable
{
public int TheValue;
public int CompareTo( object obj )
{
MyClass mc = (MyClass) obj; if ( this.TheValue < mc.TheValue )
return -; if ( this.TheValue > mc.TheValue )
return ; return ;
}
}
现在,MyClass类实现了IComparable接口,它可以用于Sort方法了。
class Program
{
static void PrintOut( string s, MyClass[] mc )
{
Console.Write( s );
foreach ( var m in mc )
Console.Write( "{0} ", m.TheValue ); Console.WriteLine( "" );
} static void Main()
{
var myInt = new[] { , , , , }; MyClass[] mcArr = new MyClass[];
for ( int i = ; i < ; i++ )
{
mcArr[i] = new MyClass();
mcArr[i].TheValue = myInt[i];
} PrintOut( "Initial Order: ", mcArr ); Array.Sort( mcArr );
PrintOut( "Sorted Order: ", mcArr );
}
}
现在,一个完整的接口实例已经完毕。
(3)使用接口注意事项:
①声明接口时:不能包含:数据成员、静态成员;只能声明:方法、属性、事件、索引器;
TIP:接口允许有任何的访问修饰符,但是接口成员是隐式public的,不允许有任何的访问修饰符,包括public。
②实现接口时:在基类列表中包括接口名称;为每一个接口的成员实现接口;
(4)接口是一种引用类型:我们不能直接通过类或对象的成员访问接口,然而,我们可以通过把类对象转换成接口类型来获取指向接口的引用。一旦有了接口的引用,我们就可以使用点号来调用接口的方法。
using System; interface IIfc1
{
void PrintOut( string s );
} class MyClass : IIfc1
{
public void PrintOut( string s )
{
Console.WriteLine( "Calling through: {0}", s );
}
} class Program
{
static void Main()
{
MyClass mc = new MyClass();
mc.PrintOut( "object" ); IIfc1 ifc = (IIfc1) mc;
ifc.PrintOut( "interface" );
}
}
下面我们看看上面的代码在内存中的分配:
(5)接口和as运算符=>天生一对
在以往使用接口引用时,我们往往会使用强制类型转换,但强制类型转换会抛出异常(异常是指代码中的意外错误,它会严重降低代码速度)。如何避免这个问题,我们可以使用as运算符,在类对象未实现接口时不会抛出异常,只会返回null。
二、看我72变:转换
(1)本质:接受一个类型的值并使用它作为另一个类型的等价值的过程;
(2)转换分类:
①预定义的转换:数字、装箱/拆箱、引用转换;
数字类型的转换详见下图:
装箱/拆箱是一个比较重要的点,现在我们来看看:
装箱(boxing)是值类型->引用类型,本质其实是创建副本。装箱是一种隐式转换,它接收值类型的值,根据这个值在在堆上创建一个完整的引用类型对象并返回对象引用。
拆箱(unboxing)是引用类型->值类型,本质把装箱后的对象转换回值类型。拆箱是显示转换。
②用户自定义的转换:隐式和显示的自定义转换;
using System; class Person
{
public string Name;
public int Age; public Person( string name, int age )
{
Name = name;
Age = age;
} public static implicit operator int( Person p )
{
return p.Age;
} public static implicit operator Person( int i )
{
return new Person( "Nemo", i );
}
} class Program
{
static void Main()
{
Person bill = new Person( "bill", ); int age = bill;
Console.WriteLine( "Person Info: {0}, {1}", bill.Name, age ); Person anon = ;
Console.WriteLine( "Person Info: {0}, {1}", anon.Name, anon.Age );
}
}
(3)is运算符:
在转换过程中,有些转换是不成功的,并且会在运行时抛出一个InvalidCastException异常。我们可以使用is运算符来检查转换是否会成功,从而避免盲目地尝试转换。
本章思维导图
附件
思维导图(jpg、pdf以及mmap源文件)下载:http://pan.baidu.com/s/1qWNOGGW
《C#图解教程》读书笔记之六:接口和转换的更多相关文章
- C#图解教程读书笔记(第1章 C#和.net框架)
C#中的主要需要记住的基础概念 CLR公共语言运行库 CIL中间语言,所有的代码都会编译成中间语言. CLI公共语言基础结构 C#的优点 C#有自动垃圾回收机制
- C#图解教程读书笔记(第15章 委托)
委托是C#的一个很重要的知识点. 1.什么是委托 委托在我认为,就是一系列格式相同的方法列表,可能就是定义的名称不一致,参数.返回值等都是一样的. 2.如何声明委托 delegate void MyF ...
- C#图解教程读书笔记(第9章 语句)
文件头的Using是Using指令,不是using语句 using (TextWriter tw = File.CreateText("xixi.txt")) { tw.Write ...
- C#图解教程读书笔记(第8章 表达式和运算符)
表达式 字面量 整数字面量 字符字面量 字符串字面量 求值顺序 优先级 结合性 与C和C++不同,在C#中的数字不具有布尔意义. 各种运算符的作用(过) 用户定义类型转换 class XiXiInt ...
- C#图解教程读书笔记(第7章 类和继承)
1.所有的类都继承自object 2.如何隐藏基类的成员 要隐藏一个继承的数据成员,需要声明一个新的相同类型的成员,并使用相同的名称. 通过在派生类中声明新的带有相同签名的函数成员,可以隐藏或掩盖继承 ...
- C#图解教程读书笔记(第6章 类进阶)
类成员声明语句由下列部分组成:核心声明.一组可选的修饰符和一组可选的特性(attribute). [特性] [修饰符] 核心声明 修饰符: 如果有修饰符,必须放在核心声明之前. 如果有多个修饰符,要有 ...
- C#图解教程读书笔记(第5章 方法)
类型推断和var关键字 从C#3.0开始,可以在变量声明的开始部分的的位置使用新的关键字var. Var关键字并不是某种特别类型的符号.它只是句法上的速记,表示任何可以从初始化的右边推断出的类型. V ...
- C#图解教程读书笔记(第4章 类:基础)
类成员包括数据成员和函数成员. 和C/C++不同,C#在类型的外部不能声明全局变量,所有的字段都属于类型,而且必须在类型声明内部声明. 和C/C++不同,方法没有返回默认类型,所有方法必须包含返回类型 ...
- C#图解教程读书笔记(第3章 类型、存储及变量)
1.C#的中的数值不具有bool特性. 2.dynamic在使用动态语言编写的程序集时使用,这个不太明白,看到后面需要补充!! 动态化的静态类型 3.对于引用类型,引用是存放在栈中,而数据是存放在堆里 ...
- C#图解教程读书笔记(第2章 C#编程概述)
这章主要是一个对于C#程序的概括解释 和C/C++不同,不是用include声明引用的头文件,而是通过using的方式,声明引用的命名空间. 命名和C/C++类似,并且也是区分大小写的,这件事情在VB ...
随机推荐
- Android之ImageSwitcher
要点: (查看Api总结) 1:ImageSwitcher 继承 ViewSwitcher, (ViewSwitcher 有继承FrameLayout ) 2: 要实现切图必须实现 ViewSwitc ...
- C++中关于文件的读写
在C++的学习过程中,我们时常要用到对文件的操作,下面我们讲一下文件的读写. 首先,读.也就是把已有的文件读到控制台上,那么如何操作呢?首先要将文件操作的输入输出流包含进去. <fstream& ...
- 准备熟悉Kaggle -菜鸟进阶
原文链接http://www.bubuko.com/infodetail-525389.html 1.Kaggle简介 Kaggle是一个数据分析的竞赛平台,网址:https://www.kaggle ...
- freeCodeCamp:Chunky Monkey
猴子吃香蕉可是掰成好几段来吃哦! 把一个数组arr按照指定的数组大小size分割成若干个数组块. 例如:chunk([1,2,3,4],2)=[[1,2],[3,4]]; chunk([1,2,3,4 ...
- text-shadow文字阴影属性用法
text-shadow:offset-x:阴影水平移动,负值时向左偏移 text-shadow:offset-y:阴影垂直移动,负值时向上移动 text-shadow:radio-bluer:阴影到实 ...
- C++基础知识易错点总结(2)
1. 若一组待排数据有序,花费时间最多的是:快速排序,T(n)=O(n^2): 2. 有 1000 个无序的整数,希望使用最快的方式找出前 50 个最大的,最佳的选择是? 快速排序:在最理想的情况下, ...
- CAD二次开发 - 可缩放块(四)
1.说明 可进行缩放性注释的对象有:文字.标注.图案填充.公差.多重引线.块及属性. 2.为图形添加.删除注释比例步骤 1)使用AnnotationScale类(在DatabaseServices命名 ...
- gc roots 垃圾回收
gc roots包括以下几个: 虚拟机栈(栈桢中的本地变量表)中的引用对象 方法区中的类静态属性引用的对象 方法区中的常量引用的对象 本地方法栈中JNI(即native方法)的引用的对象 java,c ...
- Spring中使用Schedule调度
在spring中两种办法使用调度,以下使用是在spring4.0中. 一.基于application配置文件,配置入下: <bean id="jobDetail" class ...
- RabbitMQ 记录
RabbitMQ 中文文档 : http://rabbitmq.mr-ping.com/description.html 官方教程译文: 一 http://blog.csdn.net/xiaoxian ...