此书为《C#入门经典(C#6.0&Visual Studio 2015)(第七版)》,购于2016年底
购买此书是因为工作需要接触部分C#代码,而那时我对面向对象编程的概念认识尚浅,工作接触的代码又比较庞大,于是寄希望于此书,希望能快速上手C#,了解基本的知识,避免闹笑话。
刚拿到这本书时,我急于求成,加上书前半部分的内容也很入门(读书时跳过了),约2、3周便利用闲暇时间读完了,这份读书笔记是今年6月左右开始整理的,希望能像当年学习高数一样仔细揣摩一下,但是仍有一些部分不求甚解(或者得了解确因为没有实例学习印象不深)。现在把书中的内容做个简单的总结,时常复习,未来学习软件架构时,作为工具也好有个参考。
第一章 C#简介
1.1 .NET Framework的含义
.NET Framework 是Microsoft为开发应用程序而创建的一个具有革命意义的平台。可运行于各种Windows\Linux版本和Mac OS,另外,一些版本可运行在iPhone和Android智能手机上。可以使用.NET Framework创建桌面程序、Windows Store应用程序、云/Web应用程序、Web API和其他各种类型的应用程序。.NET Framework的设计方式确保它可以用于各种语言,包括C#、C++、VB、JS甚至一些旧语言,所用这些语言都可以访问.NET Framework,他们彼此之间还可以通信。
1.2 .NET Framework 的内容
.NET Framework主要包含一个庞大的代码库,可以在客户语言(如C#)中通过面向对象编程技术(OPP)来使用这些代码。这个库包括多个不同的模块,这样就可以根据需要得到的结果来选择使用各个部分。其目的是,不同操作系统可以根据各自的特性,支持其中的部分或全部模块。部分.NET Framework库定义了一些基本类型。类型是数据的一种表达方式,制定最基本的类型有助于使用.NET Framework的各种语言之间进行交互操作,这称为通用类型系统(Common Type System,CTS)。
除提供这个库外,.NET Framework还包含.NET公共语言运行库(Common Language Runtime,CLR),它负责管理用.NET库开发的所有用用程序的运行。
1.2.1 使用.NET Framework编写应用程序
使用.NET Framework编写应用程序,就是使用.NET代码库编写代码(使用支持Framework的任何一种语言)。本书用VS进行开发,VS是一种强大的集成开发环境,支持C#(以及托管和非托管C++、VB和其他一些语言)。这个环境便于把.NET功能集成到代码中。我们创建的代码完全是C#代码,但使用了.NET Framework,并在需要时利用了VS中的其他工具。
为执行C#代码,必须把他们转化为目标操作系统识别的语言,即本机代码(native code)。这种转换称为编译代码,由编译器执行。但在.NET Framework下,此过程包含两个阶段。
1. CIL和JIT
在编译.NET Framework库的代码时,不是立即创建专用操作系统的本机代码,而是把代码编译为中间通用语言(Common Intermediate Language,CIL)代码,这些代码并非专门用于任何一种操作系统,也非专用于C#。其他.NET语言也会在第一阶段编译为这种语言。开发C#应用程序时,这个编译步骤由VS完成。
Just-In-Time(JIT)把CIL编译为专用于OS和目标机器结构的本机代码。这样OS才能执行应用程序。这里编译器的名称JIT反映了CIL代码仅在需要时才编译的事实。这种编译可以在应用程序的运行过程中动态发生,不过开发人员一般不需要关心这个过程。除非编写功能十分关键的代码,否则知道这个编译过程会在后台自动运行,不需要人工干预就可以了。
2. 程序集
编译应用程序时,所创建的CIL代码储存在一个程序集中。程序集包括可执行的应用程序文件(可直接在Windows中运行,不需要其他文件,扩展名为.exe)和其他应用程序使用的库(其扩展名是.dll)。
除包含CIL代码外,程序集还包含元信息(即程序集中包含的数据信息)和可选资源(CIL使用的其他数据,例如声音和图片文件)。元信息允许程序集是完全自描述的。当然,不必把运行应用程序所需的所有信息都安装到一个地方。可以编写一些代码来执行多个应用程序所要求的任务,此时,可以把这些可重用的代码放在所有应用程序都可以访问的地方。在.NET Framework中,这个地方是全局程序集缓存(Global Assembly Cache,GAC),把代码放在这个缓存中是很简单的,只需把包含代码的程序集放在包含该缓存的目录中即可。
3. 托管代码
在将代码编译为CIL,再用JIT编译器编译为本机代码后,CLR的任务尚未完成,还需要管理正在执行的用.NET Framework编写的代码(这个执行代码的阶段通常称为运行时(runtime))。即CLR管理着应用程序,其方式是管理内存、处理安全性以及允许进行跨语言调试等。相反,不受CLR控制运行的应用程序属于非托管类型,某些语言(如C++)可以用于编写此类应用程序,例如访问操作系统的底层功能。但C#只能编写在托管环境中运行的代码。我们将使用CLR的托管功能,让.NET处理与操作系统的任何交互。
4. 垃圾回收
托管代码最重要的一个功能是垃圾回收(garbage collection)。
第二章 变量和表达式
第二、三章 编写C#程序
原书本章内容实在太简单,目的是让编程小白写“Hello World”,不堪在此一提,这里直接和原书的第三章合并。
2.1 C#的基本语法
在VS中Tools|Options中可更改默认的代码样式。在注释符号///后面的文本可以在编译时提取,用于创建XML文档(必须遵循XML文档规则)
2.2 C#控制台应用的基本结构
使用#region和#endregion关键字来定义可以展开和折叠的代码区域(以#开头的任意关键字实际上是一个预处理指令,严格来说并不是C#关键字)
2.3 变量
使用标准类型可以在不同语言之间交互操作(.Net Framework)。有时候一些字面值有多种可能类型,如100可能为long,可能为int,也可能为double,可以通过后缀,并根据上下文判断其类型:
类型 | 后缀 | 实例 |
---|---|---|
float | f或F | 1.5f |
double | 无\d\D | 1.5 |
uint\ulongstripes | u或U | 100U |
long\ulong | l或L | 100L |
字符串的字面值中特殊符号可用转义符代替,也可在字符串的双引号之前加一个@字符,避免结束字符串,如@“Beijing‘s string.”
注意字符串本质上是引用类型,而非值类型,因此可赋值null,表示字符串变量不引用字符串。
注意变量声明后最好紧跟着变量初始化,原因是声明时不会为分配内存空间,初始化时会
int i;
string test;
for(i=0;i<10;i++)
{
test="Line"+Convert.ToString(i);
WriteLine($"{test}");
}
WriteLine($"{test}");//这里出错了,原因是test未初始化
2.4 表达式
默认情况下,C#代码包含在全局名称空间中。使用namespace关键字为花括号中的代码块显式定义名称空间。如果一个名称空间中的代码需要使用在另一个名称空间中定义的名称,就必须包含对该名称空间的引用,不同名称空间级别之间用句点(.)连接。
特别注意:using语句本身不能访问另一个名称空间中的名称,除非名称空间中的代码以某种方式链接到项目上,或者代码是在该项目的源文件中定义的。using语句仅仅是为了我们便于访问这些名称。
2.5 名称空间
使用关键字using添加名称空间,在C#6中新增关键字using static,允许把静态成员直接包含到C#程序的作用域中,例如可使用该关键字将System.Console静态类中的WriteLine()静态方法包含到作用域中:
using static System.Console.WriteLine;
这样,访问WriteLine方法时就不加必限定符号了。
第四章 流程控制
使用三元运算符< test >?< If True> : < If False>使代码更整洁。
在switch语句中每个case必须有break; 在最后要用default: 执行不属于以上任一case的情况。也可以对case进行叠加处理,例如:
switch (<testVar>)
{
case <value1>:
case <value2>:
…
break;
case <value3>:
…
break;
default:
…
break;
}
第五章 变量的更多内容
5.1 强制转换
强制转换时注意判断溢出,例如将double转化为short时,
double A=1000000;
unsigned char B;
B=checked((unsigned char)A);
以上代码在运行时会崩溃,并提示错误信息,(疑问,这个功能有什么意义呢,不能抛出异常吗)
也可以在编译时自动为所有类似表达式添加默认检查,设置方法为:在solution property中打开build设置,在advanced选项卡中激活Check for arithmetic overflow/underflow。
5.2 枚举
用关键字enum声明枚举
enum orientation:byte
{
north=1,
south=2,
east=3,
west=4
}
orientation myDirection=orientation.east;
5.3 结构
使用关键字struct声明结构
struct route
{
public orientation direction;
public double distance;
}
5.4 数组
记录几个实用的数组声明/初始化小例子:
int[] myArray={
5,9,10,99};
int[] mrArray=new int[5] {
5,9,10,99,0};//注意初始化列表必须和数组大小相对应
int[] myArray;
myArray=new int[5];//默认初始化为0
foreach循环是一种简便定位数组中的元素的方法,与for循环不同,foreach只能做只读循环。
foreach(string friendName in friendNames)
{
WriteLine(friendName);
}
多维数组的定义和引用
double[,] hillHeight={
{
1,2,3,4},{