20110222C#程序员参考手册
.Net Framewrok两个组成部分:一个是称为公共语言运行(CLR)的运行时环境(类似于Java虚拟机),和一个提供在Windows平台上开发应用程序所需的几乎所有常见功能的很大的类库。
公用语言运行时(CLR)是.Net Framewrok的真正核心,管理代码在运行时的执行。C#编译器将代码编译成中间语言(IL)的低级语言。在运行时,IL代码使用一个JIT编译器把中间语言编译为本机代码。JIT编译器允许根据使用的操作系统和硬件进行代码优化,因此在很大程度上抵消了编译性能的成本。运行在CLR下的代码称为托管代码,托管代码的主要好处是垃圾收集。.NET垃圾收集器会负责销毁无法再从任何线程访问的托管对象,并释放它们占用的内存。
通用类型系统(CTS):由于CLR在应用程序安装前,所有的.NET代码都要编译为IL的低级语言,所以各个语言之间的高度互操作性才成为可能,通用类型系统的作用是规范了方法调用的方式,并为所有的语言提供了相同的类型系统。CTS定义了所有语言中的基本数据类型,和复杂数据类型的格式与行为,但是不是各种语言的编译器都支持CTS的每一种功能,但是每种语言编译器必须都支持CTS的一个子集,即公用语言规范(CLS)从而保证用一种语言编写的代码就可以从任何其他一种.NET语言识别。
栈和托管堆:.NET使用两种不同的物理内存块来存储数据:栈和托管堆。
1. 栈在一个先入后出的基础上储存数据,值类型总是在内存中占用一个预定义的字节数(例如,int类型占用4个字节,而String类型占用的字节数会根据字符串的长度不同而不同)。.NET维护一个栈指针,它包含栈中下一个可用内存空间地址;
当一个变量离开作用域时,栈指针向下移动被释放变量所占用的字节数,所以它指向下一个可用地址(因为栈是先入后出,栈中最上面的变量总是比下面的变量先离开作用域)。
2. 引用变量也利用栈,但这时栈包含的只是对另个内存位置的引用,而不是实际值。这个位置是托管堆的一个地址。托管堆,也维护一个指针,它包含堆中下一个可用内存空间地址,堆不是先入后出,因为对对象的引用可以在我们的程序中传递。为了在不使用在堆中分配的内存时将它释放,.NET定期执行垃圾收集。垃圾收集器递归的检查应用程序中所有的对象引用;引用不再有效的对象的使用的内存无法从程序中访问是,该内存就可以回收。
值类型:分为三种即枚举,内建值类型和用户定义的值类型,或成为结构。直接保存它们的数据存放在栈中,按值传递即当一个值类型的参数传递给一个方法时,该值的一个新的拷贝被创建,对参数所做的任何修改都不会斗志传递给方法的变量被修改。
引用类型:包含引用,不包含实际的值,所以对方法体内参数的所做的任何修改将影响传递给方法调用的引用类型的变量。包括委托,接口,类,数组。
当声明字符串变量s1时,一个值被压入栈中,它指向堆中的一个位置。引用存放在地址1243044中,而实际的字符串存放在堆的地址12262032种,当该字符串传递一个方法时,在栈上对应输入参数声明了一个新的变量(这次是在地址1243032上),保存在引用变量,即堆中内存位置中的值被传递给这个新的变量。
确定类型:
obj.GetType() == typeof(string);
装箱和拆箱:值类型和引用类型都是派生于Object类,所以意味着任何一个以对象为参数的方法,都可以给他传递一个值类型。相似地,值类型可以调用一个Object类方法。值类型变量被隐式转换为引用类型被称为装箱,相反则为拆箱。
static void Main(string[] args) { int j = 22; object obj = (object)j;//装箱 int i = (int)obj;//拆箱 }
数组是包含相同类型元素的一种数据结构。通过一个整形的下标访问。Array类代表一个不可变的对象数组,可以是多维的。ArrayList可以使用大小随意改变的一个一维数组。
创建一维数组:
static void Main(string[] args) { int[] array = new int[5]; for (int i = 0; i < array.Length; i++) { array[i] = i * 2; Console.WriteLine(array[i]); } }
创建多维数组:每行长度相同(即列数相同)的数组称为矩形数组,每行长度不同的数组称为锯齿形数组。
static void Main(string[] args) { int[,] array = new int[2, 3]; for (int i = 0; i < array.GetLength(0); i++) { for (int j = 0; j < array.GetLength(1); j++) { array[i, j] = i + j; Console.WriteLine(string.Format("{0}:rows,{1}:colunms is value:{2}", i, j, array[i, j])); } } }
数组属性和方法:Sort():
string[] array = { "Jon", "come", "from", "China" }; System.Array.Sort(array); foreach (string str in array) { Console.WriteLine(str); }
数组引用语义:数组和所有的引用类型一样,这意味着数组类型的变量如果没有初始化,就是一个空引用——不是空数组。
static void Main(string[] args) { string[] array = { "Jon", "come", "from", "China" }; PassByValue(array); Console.WriteLine(array[0]);//output:Chinese string[] arrayref = { "Jon", "come", "from", "China" }; PassByref(ref arrayref); Console.WriteLine(arrayref[0]);//output:a string[] arrayout = { "Jon", "come", "from", "China" }; PassByout(out arrayout); Console.WriteLine(arrayout[0]);//output:a } public static void PassByValue(string[] _array) { _array[0] = "Chinese"; _array = new string[] { "a", "b", "c", "d" };//指向新的内存中堆地址; } public static void PassByref(ref string[] _array)// 传递到 ref 参数的参数必须最先初始化, //实际将整个数组传递过,即按值传递 { _array[0] = "Chinese"; _array = new string[] { "a", "b", "c", "d" }; } public static void PassByout(out string[] _array)// out 参数传递的变量不必在传递之前进行初始化, //但被调用的方法需要在返回之前赋一个值。 实际将整个数组传递过,即按值传递 { _array = new string[] { "a", "b", "c", "d" }; }
静态构造函数:通常用于初始化静态的数据成员,与一个类型有关,而不是与类型的实例相关,不允许有访问修饰符,不能显示的调用静态构造函数,它在加载类时被运行时调用一次——在创建类的任何实例和引用类的任何静态成员前。
class Program { static void Main(string[] args) { Console.WriteLine(Static.pi); } } class Static { public static float pi; static Static() { pi = 3.14f; } }
Using:当using语句应用与对象时,using语句后面的代码块执行后马上处理占用的资源。资源的处理是通过调用对象的Dispose()方法。其二是名称空间的引用。
继承:是面向对象的支柱之一,是OOP瑰丽代码复用的一种方式。通过扩展实现基类的功能来创建一个新的派生类。C#只支持单一继承。
用户定义类型之间的强制转换:某些用户定义的类型之间也可以进行转换,如类,结构和接口。大多数转换要求在转换的原类型或目标类型内定义强制转换,但许多转换允许隐式的进行,不可编写额外的代码。
结构:和类相似的一种封装结构,和类不同是结构是值类型,存放在内存中成为栈道地方,结构通常存放简单的数据类型,在内存中有固定大小的实体的集合。和存放在堆中的类相比,具有性能上的优势。原因之一,值类型的分配快于引用类型。原因之二,存放在栈中的值一离开作用域就立即被回收,不用等待垃圾收集器来完成工作。
但是,如果把结构作为参数传递给一个方法,这种做法就会成为一个问题。当引用类型传递方法时,传递的只是对对象的引用。而对于结构,在传递之前要复制它的一个完整的副本。和引用类型相比,结构越复杂,复制造成的性能开销越大,因此,结构应该只用来表示小的数据结构。
结构既不能定义无参数的构造函数,有不能定义析构函数。无参的构造函数是由运行时提供的,用来将所有的数据成员初始化为默认值,而结构定义的构造函数必须为结构包含的每个字段赋值。
结构不支持实现继承,虽然它们可以提供一个或多个接口的实现。结构隐式的从ValueType类和object类继承,但是也隐式的是sealed类型,也就是说他不能作为其他类的基类。从而造成结构的成员不能声明为virtual,同时也不能结构定义为abstract。
接口:所有成员隐式的为public和abstract。
New关键字可以应用于接口来表示它的一个成员隐藏了被继承接口的一个成员。
public class BaseC { public static int x = 55; public static int y = 22; } public class DerivedC : BaseC { // Hide field 'x'. new public static int x = 100; static void Main() { // Display the new value of x: Console.WriteLine(x); // Display the hidden value of x: Console.WriteLine(BaseC.x); // Display the unhidden member y: Console.WriteLine(y); } } /*Output: * 100 * 55 * 22 */
对同一成员同时使用 new 和 override 是错误的做法,因为这两个修饰符的含义互斥。 new 修饰符会用同样的名称创建一个新成员并使原始成员变为隐藏的。 override 修饰符会扩展继承成员的实现。 在不隐藏继承成员的声明中使用 new 修饰符将会生成警告。
但一个类既继承一个基类有实现一个接口时,基类放在最前面。
枚举:是一个便利的值类型,它把名称映射为整型值。访问修饰符可以有public或internal,默认是internal。枚举定义了包含枚举名和值的一个列表,值可选的,若不指定,默认从0开始。
定义枚举:
public enum Planted { Earth = 1, Mars = 2, Venus = 3, Jupiter = 4 }
静态字段:无论创建了多少类的实例,静态字段只有一个副本。使用静态字段会在必要的情况下将包含相关类型的程序集或模块加载到运行时。和它比起来,实例字段只在创建类型的一个实例时才能使用。
常量字段:被看作固定值,const关键字声明。在声明时必须赋值,并且该值在编译时必须是可计算的,隐式为静态的,不能既把一个字段声明为const,又声明为static。而且只能用于内建的值类型,string,enum。除了字符串外,不能把引用类型定义为常量字段。
只读字段:一旦赋值就不能改变,readonly 关键字声明。可以声明它的地方赋值,或者在它所属类型的构造函数中赋值,但在别的地方就不行,也可以运行时求值的变量的赋值,如果不给只读字段赋值,那值类型使用0,引用类型为空值。可以为静态的,但必须显示的为静态。
Lock语句:提供对引用类型变量的同步访问
虚方法:可以被派生类覆盖的方法。
class TestClass { public class Dimensions { public const double PI = Math.PI; protected double x, y; public Dimensions() { } public Dimensions(double x, double y) { this.x = x; this.y = y; } public virtual double Area() { return x * y; } } public class Circle : Dimensions { public Circle(double r) : base(r, 0) { } public override double Area() { return PI * x * x; } } class Sphere : Dimensions { public Sphere(double r) : base(r, 0) { } public override double Area() { return 4 * PI * x * x; } } class Cylinder : Dimensions { public Cylinder(double r, double h) : base(r, h) { } public override double Area() { return 2 * PI * x * x + 2 * PI * x * y; } } static void Main() { double r = 3.0, h = 5.0; Dimensions c = new Circle(r); Dimensions s = new Sphere(r); Dimensions l = new Cylinder(r, h); // Display results: Console.WriteLine("Area of Circle = {0:F2}", c.Area()); Console.WriteLine("Area of Sphere = {0:F2}", s.Area()); Console.WriteLine("Area of Cylinder = {0:F2}", l.Area()); } } /* Output: Area of Circle = 28.27 Area of Sphere = 113.10 Area of Cylinder = 150.80 */
密封方法:不能在派生类中覆盖,总和overwrite连用。
public sealed override double GetArea() { return Math.PI; }
Extern关键字:用来指明方法在外部用一种非.NET语言实现。放在访问修饰符和返回类型之间。

浙公网安备 33010602011771号