# C#和.NET框架
CLR:执行环境称,公共语言运行库
BCL:基类库,是.NET框架使用的一个大的类库,而且也可以在你的程序中使用。
CLR, BCL和C#被设计的完全面向对象,并形成良好的集成环境。
CLR里面有自动垃圾收集,自动管理内存。
互操作性:
一种.NET语言写的程序可以使用甚至是继承另外一种.NET语言写的类,只需要遵循一定的规则即可。所以.NET框架是语言无关的。
平台调用:允许.NET的代码调用并使用非.NET的,但是通过标准Win32 DLL导出的纯C函数的代码,比如Windows API。
类型,存储和变量
6种用户可以自己定义的类型:
栈:
栈存储的几种类型的数据:
1)某些类型变量的值
2)程序当前的执行环境
3)传递给方法的参数
堆:
堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据。与栈不同,堆里的内存可以任意顺序存入和移除。
垃圾处理机制:
异常
异常类:
BCL定义了许多类,每一个类代表一个指定的异常类型。当一个异常发生时,CLR:
1)创造该类型的异常对象
2)寻找适当的catch子句以处理它
catch子句处理异常,有三种形式,允许不同级别的处理。
带对象的特定catch子句,可以提供最多的关于异常的信息。它匹配该指定类的异常,或派生自它的异常类的异常。它还给出一个异常实例,称为异常变量,它是一个对CLR创建的异常对象的引用。可以在catch子句块内部访问异常变量的属性,以获取关于引起的异常的详细信息。
catch语句有顺序:
finally块:
finally语句始终会被执行
注:即使try里面有return语句,finally语句也会在返回到调用代码之前执行。
处理流程:
抛出异常:
可以使用throw语句使代码显示地引发一个异常。throw语句的语法如下:
throw ExceptionObject;
结构
结构是程序员定义的数据类型,和类很相似。
最重要的区别:
1)类是引用类型而结构是值类型。
2)结构是隐式密封的,这意味着它们不能被派生
对结构赋值:
把一个结构赋值给另一个结构,就是从一个结构中把值复制到另一个结构,这和复制类变量不同,复制类变量时只有引用被复制。
结构可以有实例构造函数和静态构造函数,但不允许有析构函数。
数组
数组类型:
C#提供了两种类型的数组
1)一维数组
2)多维数组,由主向量中的位置组成的,每一个位置本身又是一个数组,成为子数组。子数组向量中的位置本身又是一个子数组。
有两种类型的多维数组:矩阵数组和交错数组
矩阵数组:
交错数组:
两种数组的样子:
Rank:返回数组维度数的属性
Length:返回数组长度(数组中所有元素的个数)的属性
存储在数组中的元素,可以使值类型,也可以是引用类型。
数组声明后,维度数就是固定的了,但是,维度长度直到数组实例化时才会被确定。
注:不能在数组类型区域中放数组维度长度。秩是数组类型的一部分,而维度长度不是类型
的一部分
数组创建:
交错数组是数组的数组。与矩形数组不同,交错数组的子数组可以有不同数目的元素。
正确:
错误:
交错数组的完全初始化不能在一个步骤中完成,由于是独立数组的数组,每一个数组必须独立创建。
1)首先,实例化顶层数组
2)其次,分别实例化每一个子数组,把新建数组的引用赋值给包含它们的数组的合适元素。
数组协变:
在某些情况下,即使某个对象不是数组的基本型,我们也可以把它赋值给数组元素,这种属性叫做协变。
委托
委托:可以认为是这样的对象,它包含具有相同签名和返回值类型的有序方法列表。
方法的列表称为调用列表,当委托被调用时,它调用列表中的每一个方法。
关键字:delegate
委托类型声明:
委托类型的声明看上去和方法的声明很类似,有返回类型和签名。返回类型和签名指定了委托接受的方法的形式。
委托是引用类型,因此有引用和对象。在委托类型声明之后,我们可以声明变量并创建类型的对象。
快捷语法:
如下:Sclass.OtherM2会被删除
为委托增加方法:
当使用+=运算符的时候,实际发生的是创建了一个新的委托。
调用委托:当委托被调用的时候,列表中的每个方法都会被调用一次。
没有参数和返回值的委托:
对象调用就是调用的上面的方法,直接类调用就是下面的方法。
调用带返回值的委托
调用列表的最后一个方法的返回值就是委托调用的返回值,其他方法的返回值都会别忽略。
调用带引用参数的委托
参数值会根据调用列表中一个或多个方法的返回值而改变:
匿名方法:
匿名方法的表达式的语法包含如下组成部分:
1)delegate类型关键字
2)参数列表,如果语句块没有使用任何参数则可以省略
3)语句块,它包含了匿名方法的代码
Lambda表达式
作用:简化匿名方法
匿名方法:MyDel de1 = delegate(int x) { return x + 1; };
改为Lambda表达式:MyDel de2 = x => x + 1;
接口
接口:表示一组函数成员而不实现成员的引用类型。其他类型,类和结构可以实现接口。
一个接口的声明:
要实现接口,类或者结构,必须要做两件事情。
1)必须在基类列表后面列出接口名称
2)必须为接口提供每一个成员的实现
声明接口:
方法,属性,事件,索引
这些函数成员的声明不能包含任何实现代码,而在每一个成员声明的主体后必须使用分号
按照惯例,接口名称必须从大写的I开始
接口声明可以有任何的访问修饰符,public,protected,internal和private
然而,接口的成员是隐式public的,不允许有任何访问修饰符,包括public。
实现接口:
只有类和结构才能实现接口。
1)在基类列表中包括接口名称
2)为每一个接口的成员提供实现
接口和as运算符:
强制转换操作会抛出异常,可以使用as运算符来避免这个问题
显示接口:
用于接口分离,因为继承的多个接口具有相同名称的成员方法
使用限定接口名称来声明,由接口名称和成员名称以及它们中间的点分隔符构成。
接口也可以继承接口,继承一个或者多个接口。
转换
转换是接收一个类型的值并使用它作为另一个类型的等价值的过程。
转换后的值应该和源值一样,但他是目标类型。
溢出检测上下文
如果我们指定一个表达式或者一段代码为checked,CLR会在转换产生溢出时抛出一个OverflowException异常
引用转换
引用类型对象由内存中的两部分组成:引用和数据。
隐式引用转换
所有引用类型可以被隐式转换为object类型
任何类型可以隐式转到它继承的接口
类可以隐式转换到:
1)它继承的链中的任何类
2)它实现的任何接口
显式引用转换
显式引用转换是从一个普通类型到一个更精确类型的引用转换
包括:
1)从object到任何引用类型的转换
2)从基类到从它继承的类的转换。