《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 ...
随机推荐
- 将Tomcat加入windows系统服务
将Tomcat加入windows系统服务 将Tomcat加入服务 1.修改bin目录中的service.bat: REM 添加下面的一行 set CATALINA_HOME=%cd% 如果从来没有安装 ...
- IOS中无缓存的图片载入
在IOS中,我们常用[UIImage imageNamed]方法获取图像,这种方法简便,容易理解.但是有个缺点,就是有缓存.这种方式 传人的图像的就是通过文件名方式文件名.如果,我们内存有限,我们就必 ...
- Daily Scrum 12.16
今日完成任务: 完善了资源界面的UI设计:解决了PDF显示相同的问题:解决了下载时有时找不到文件的问题,因为上届建了upload和resource两个文件夹存文件,写代码时候写乱套了. 明日任务: 黎 ...
- jetbrains产品激活方式(WebStorm,Pycharm有效)
注册时,在打开的License Activation窗口中选择"activation code",在输入框输入下面的注册码 43B4A73YYJ-eyJsaWNlbnNlSWQiO ...
- cxf+spring+数字签名开发webservice(一)
数字证书的准备 下面做的服务端和客户端证书在例子中无法加解密,不知道什么原因,我是使用正式环境中的客户端和服务端进行开发测试的,所以需要大家自己去准备证书,或者有人知道为什么jdk生成 ...
- [C#基础]ref和out的使用
在C#中如果需要把值类型转换成引用类型传递其他方法中并使其原来值发生改变,使用 ref 和 out 转换成引用类型传递. 1. ref : 使用ref之前需要定义变量并初始化(必须初始) class ...
- 解决EasyUI动态添加标签渲染问题
以下代码用于Js脚本中: var Work_Content_Back = "<table width='99%' class='table' style='margin-bottom: ...
- Mysql数据库表关于几个int类型的字符长度
Data type Range Storage bigint -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,8 ...
- 纯css实现模块阴影变色效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Python基于pandas的数据处理(一)
import pandas as pd, numpy as np dates = pd.date_range(', periods=6) df = pd.DataFrame(np.random.ran ...