C#中变量的命名:
在C#中,标识符是区分大小写的。推荐的命名约定建议如下:
对于变量名和参数名,使用Camel大小写规则,该规则要求除了第一个单词外,其他单词的首字母大写,如bookTitle;
对于方法名和其他标识符,使用Pascal大小写规则,该规则要求每个单词的首字母都大写,如GetBookTitle;
C#数据类型:
1、值类型
(1)简单类型,如int double char
(2)枚举类型,enum E
(3)结构类型,struct S
(4)可以为null的类型,其他所有具有null值的类型的扩展
2、引用类型
(1)类类型
A、其他所有类型的最终基类,object
B、Unicode字符串类型 string
C、class C形式的用户自定义类型
(2)接口类型 Interface
(3)数组类型 一维数组和多维数组
(4)委托类型 delegate int D
实现值类型和引用类型之间的转换: 装箱和拆箱
装箱:将一个值类型数据隐式或显示转换为object类型数据,或者把这个值类型转换成一个被该值类型应用的接口类型。
拆箱:将一个对象类型显示转换成一个值类型,或将一个接口类型显示的转换成可执行该接口的值类型。
C#数据的输入输出(在Console程序中),使用函数Console.ReadLine(), Console.WriteLine()等。
int a = Convert.ToInt32(Console.ReadLine()); //将console输入的字符串,转换为int32形式
Console.WriteLine(a + "hello"); //将a转换为字符串,同时加上另一个字符串,输出
可以为null的类型: T?
可以为null的类型表示可赋值为null值的类型变量,其取值范围为其基础值类型正常范围内加一个null值。如bool? (Nulllable<bool> )的值包括true, false, null。
可以为null类型的赋值, int? A = 10
类型转换:
隐式转换、显式转换、Convert.Toxx函数
在C#代码中,如果在未检查的上下文中执行,整型间的显式数字转换或算术运算可能造成溢出,从而导致错误。使用checked关键字进行类型检验。
int j = checked(i + 1); //检测是否会溢出
可以在编译器中设置/checked 或/unchecked 进行全局检验。
关系和类型测试运算符
==, >=, <= , >, <, != 等传统的比较运算符, x is T, x as T
(1)关系运算符的优先级相同;
(2)对于两个预定义的数值类型,关系运算符按照操作数的大小进行比较
(3)对于string类型,关系运算符比较字符串的值,即按照ascii从左到右一一比较,直到出现不同的字符,进行比较大小。
(4)对于string类型之外的引用类型,如果两个操作数引用同一个对象,则==返回相等;否则返回 !=
(5)int和System.Int32是相同的数据类型。
x is T: 判断数据x是否属于类型T
x as T: 尝试将x转换为类型T, 如果成功,返回转换为T类型的x, 否则返回null.
逻辑运算符
!, &, | , ^, &&, ||
! 逻辑非, & 逻辑与, | 逻辑或
&& 短路与: A&&B 如果A 为false,则不必计算B 的布尔值,直接判定为false
|| 短路或: A || B, 如果A 为 true, 则不必计算B的布尔值,直接判定为true
字符串运算符
字符串运算符只有一个 +, 表示将两个字符串连接,当其中一个操作数是字符串类型或两个操作数都是字符串类型时,则+ 运算符执行字符串连接操作。
位运算
~ 按位求补, << 操作数左移, >> 操作数右移, & 按位逻辑与, | 按位逻辑或, ^ 按位逻辑异或
(1)按位求补运算~ 是为 int、uint、long和ulong类型预定义的,对操作数执行求补操作,其效果相当于反转每一位。
(2)左右移操作符的第二个操作数必须为int 类型
程序for循环结构
可以使用foreach 进行循环操作;
foreach( 类型名称 变量名称 in 数组或集合名称)
{ 操作}
异常处理
try{ 尝试执行可能触发异常的代码段 }
catch( xxException e)
{ 在异常发生时执行的代码}
finally{ 最终必须执行的代码(即时发生异常), 如释放资源等}
数组和指针
C#中数组的属性;
(1)数组使用类型声明,通过数组下标(或索引)来访问数组中的数据元素
(2)数组可以是一维数组、多维数组或交错数组
(3)数组元素可以为任意类型,包括数组类型
(4)数组下标(索引)从0开始
(5)数组元素的默认值为0, 引用类型的默认值为null
(6)交错数组是数组的数组,因此它的元素是引用类型,默认值为null
(7)数组中的元素总数是数组中各维度长度的乘积
(8)通过.NET框架中的System.Array类来支持数组。因此,可以利用该类的属性和方法来操作数组
使用数组时需要注意;
(1)数组必须先声明,因为数组为引用类型,数组变量的声明只是为数组实例的引用留出空间。
声明一维数组:int [] A;
(2)数组在声明后必须实例化才能使用。数组实例在运行时使用new 运算符动态创建,new运算符指定新数组实例的长度,new运算符自动将数组的元素初始化为相应的默认值。
(3)初始化例子:int []A = new int[3]{1, 3, 5} ,简化为 int [] A = {1, 3, 5}; 一维数组,含有三个元素,
一旦要为数组指定初始化值,就必须为数组的所有元素指定初始化值,指定值的个数必须严格等于数组的长度。
一维数组: int [] A; A = new int[4]; int []A = new int[3]{1, 3, 5} ,简化为 int [] A = {1, 3, 5};
多维数组 : int [ , ] A = new int[4, 3]; int [ , ,] B = new int[3, 5, 2] //三维数组
int [, ]array = new int[2, 2]{ {1, 2}, {3, 4}}; int [, ]array = new int[ , ] { {1, 2}, {3, 4}}; int [ , ] array = { {1, 2}, {3, 4}}
交错数组: 交错数组是元素为数组的数组,数组的数组。交错数组的元素的维度和大小可以不同,交错数组同样需要声明、实例化并且初始化后才能使用。
int [][] A = new int[3][]; A[0] = new int[5]; A[1] = new int[3]; A[2] = new int[4];
int [][] A = new int[] []
{ new int[]{1, 2, 3}, new int[]{5, 3, 2}, new int[] {3, 2}}
例:混合使用多维数组和交错数组 int [] [ , ] A = new int[3] [ , ] { new int[ , ]{ {1, 2}, {2, 3}}, new int [ , ]{ {1, 1}, {2, 2}}, new int [ , ] { { 3, 4}, {5,6}}}
作为对象的数组::
C#中,数组实际上是对象,数组类型是从Array类派生而来的引用类型。 Array类是所有数组类型的抽象基类型。System.Array类提供了许多方法和属性,可用户数组的复制、排序等操作处理。如Clear(), Clone(), CopyTo(), Copy() , GetLength()等
为了保证类型安全,默认情况下,C#不支持指针,从而避免了程序的复杂性。但在某些情况下,可能需要通过指针调用操作系统API函数、访问内存映射设备,或实现一些以时间为关键的算法。C#中使用unsafe关键字,可以定义不安全上下文,然后在不安全上下文中使用指针。
在公共语言运行时(CLR)中,不安全代码是无法验证的代码,其安全性无法由CLR进行 验证,使用不安全代码可能会引起安全风险和稳定性风险,程序员必须确保代码不会引起安全风险或指针错误。 CLR只对在完全受信任的程序集中的不安全代码执行操作,在C#中,为了编译不安全代码,必须使用/unsafe 编译应用程序。 可以将一个类、一个方法、代码块或字段标记为 unsafe, 如
public unsafe void A()
int * p: p是指向整数的指针; int **p:p是指向整数的指针的指针; int * [] p p是指向整数的指针的一维数组 ,但没有指向数组的指针。
(1)指针不能指向对象引用或会包含引用的结构,因为即使有指针指向对象引用,gia对象引用也可能会被执行垃圾回收,从而造成指针指向的内存空间包含的数据类型无效。
(2)void *类型表示指向未知类型的指针。因为目标类型是未知的,所以不能对void*类型的指针应用间接寻址运算符*, 也不能对这样的指针执行任何算术运算。但是void* 类型可以强制转化为其他任何类型的指针,反之亦然。
(3)指针可以为null,值为null 的指针表示指针没有指向有效的内存地址,针对null指针的操作将会出现异常。
(4)指针类型是单独的类型,与值类型或引用类型不同,指针类型不从object继承,而且不存在指针类型和object之间的转换。具体而言,指针不支持装箱和拆箱操作,但是允许不同指针类型之间以及指针和整型之间进行转换。
(5)指针分配内存,使用stackalloc。 stackalloc关键字用于不安全的代码上下文中,以便在堆栈上分配内存块。 int *fib = stackalloc int[100];
(6)关于fixed语句。
a) fixed语句只能出现在不安全的上下文中。
b)fixed语句禁止垃圾回收器重定位可移动的变量
c)fixed语句还可用于创建固定大小的缓冲区
d)fixed语句设置指向托管变量的指针并在statement执行期间钉住该变量。如果没有fixed语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知的重定位变量,C#编译器值允许在fixed语句中分配指向托管变量的指针
e)无法修改在fixed语句中初始化的指针。
类和对象
类是C#语言的核心,C#中的一切类型都是类,所有的语句必须在类内。.NETFramework类库包含大量解决通用问题的类,一般可以通过创建自定义类和使用.NETFramework类库来解决实际问题。
创建对象:使用new运算符创建类的实例,该运算符为新的实例分配内存,调用构造函数初始化该实例,并返回对该实例的引用。类名 对象名 = new 类名([参数表])
对象使用:类的对象使用 ”."操作符来引用类的成员。引用时,必须符合权限。
对象比较:用new创建一个类的对象时,将在托管堆中为对象分配一块内存,每一个对象都有不同的内存。代表对象的变量存储的是存放对象内存的地址。因此两个不同的对象,即时他们的所有成员的值或代码都相同,他们也是不相等的。但是,如果将一个对象赋值给另一个对象,则他们的变量都将保存同一块内存的地址,即两个对象是相同的。如果改变其中一个对象的状态(成员的值),那么也会影响另一个对象。
访问修饰符
1)public: 访问不受限制
2)protected:访问仅限于此类或从此类派生的类
3)internal:访问仅限于此程序(类所在的程序,即同一个编译单元,dll或exe中)
4)protected internal:protected或者internal,即访问仅限于此程序或从此类派生的类。
5)private:访问仅限于此类
当没有定义访问修饰符时,类成员默认访问修饰符为internal,即此类只能被定义它的程序使用。
嵌套类:
类的定义是可以嵌套的,在内部定义其他的类,类内声明的类称为内部类或者嵌套类。在编译单元或命名空间内声明的类成为顶级类,也成为包含类或者非嵌套类。嵌套类型默认为private。嵌套类也可以设置为public,internal等。
在理想情况下,嵌套类型仅由其包含类型进行实例化和使用。如果需要在其他类型中使用该嵌套类型,则建议定义单独的顶级类,避免使用嵌套类。
如果类A是类B的内部类,当需要在内部类A的内部访问类B的实例成员时,可以在类B中将代表类B的实例的this指针作为一个参数传递给内部类A的构造函数。这样类B中含有成员类A, 同时类A中保存类B的引用。
嵌套类的访问:内部类可以访问包含它的那个类可访问的所有成员,包括该类自己的具有private和protected声明的可访问性成员。这样内部类对象中可以new一个外部类对象,但实例化之后,该外部类对象和该内部类对象所属的外部类对象不是同一个。
分部类:
分部类