C# 语言基础
.NET 一个运行库和一个全面的基础类库。
.NET Framework
NET 平台主要有几三个构造块组成,如下:
CLR Common Language Runtime,表示的是公共语言运行库。
CLR 的主要作用是为我们定位、加载和管理.NET 类型,同时也负责一些低层细节的工作,如内存管理、应用托管、处理线程、案例检查等。CTS Common Type System,表示公共类型系统。
CTS 完整描述了运行库所支持的所有可能的数据类型和编程结构,指定了这些实体间如何交互、也规定了它们在 .NET 元数据格式中的表示(关于元数据,可以从网上获取参考资料)。CLS Common Language Specification,它表示的是公共语言规范。
CLS 定义了一个让所有 .NET 语言都支持的公共类型和编程结构的子集。这样,如果构造的 .NET 类型仅公开与CLS兼容的类型,那么可以肯定其他所有支持 .NET 的语言都能使用他们。反之,如果使用了不兼容的,就不能交互。
文档注释:符号是3条斜线“///”,定在类、方法或属性的前面。
数组的静态初始化
使用静态初始化时,数组的声明与初始化必须放在同一条语句中,不能分开写;如:
int[] ages = { 20, 21, 25, 28, 30 } ;
数组的动态初始化
声明与初始化可以分开或一起写 数组名 = new 数组类型[长度] 自动分配默认值
int[] ages = new int[5] { 20 , 22 , 24 , 26 , 30 } ;
foreach 是一种更简单更明了的读取数组元素的语句。
特点:
—用于读取容器类数据(数组、集合等)
— 适合一次性读取全部元素
—不能修改元素
foreach( 数据类型 变量名 in 数组名)
{
//变量名此时表示的就是数组中的每一个元素
}
二维数组
数据类型[,] 数组名 = new 数据类型[行数,列数]
参数修饰符
- out修饰符
定义为带有输出参数(通过关键字out)的方法有义务在退出这个方法之前,给参数赋一个恰当的值(如果不这样做,会出现编译错误)调用该方法时,也需要使用out修饰符
允许传递未分配(未初始化)的数据
通过它,调用者只使用一次方法调用就能获得多个返回值。
1 | static void Add(int x, int y, out int addValue, out int subValue){ |
- ref修饰符
输出参数不需要在它们被传递给方法前初始化,因为方法在退出之前必须为输出参数赋值。
引用参数必须在它们被传递给方法之前初始化,因为是在传递一个对已存在变量的引用。如果不赋给它初始值,就相当于木对一直未赋值的本地变量进行操作。
方法重载
在同一个类的一组方法(至少大于或等于两个方法)
这些方法的方法名称相同,参数类型或参数个数不同
能否构成方法的重载,跟方法的返回值没有关系
protected
一般用于含有继承关系的子父类当中。可以由定义它们的类型及其任意子类使用,但外部类无法通过 C# 的“.”操作符访问。internal:内部的
用于修饰:类型或者类型成员
作用范围:当前项目下的所有类
使用internal修饰类中的字段或方法,在当前项目所有类下都可访问,但是其它项目是访问不到的。protected internal :受保护的内部的
用于修饰:类型成员或者嵌套类型
如果使用了 protected internal 关键字,作用范围在定义它们的程序集、类以及派生类中可用。
封装性
广义封装
更多的是从整个项目的项目架构设计上考虑的,比如说完成一个项目时,该项目有几个模块组件,每个模块应该包含哪些对象,对象与对象之间的关系,模块与模块之间的关系划分等,这些可以使用广义封装解决狭义封装
对象的内部数据不应该从对象实例直接访问。对象数据应该被定义为私有的,如果调用者想改变对象的状态,就要间接使用公共成员。
狭义封装,表示的是是对一个类中的成员(字段、方法等)的访问权限(作用范围)进行的一种限制操作。
通常情况下,使用C#中的访问控制符(又叫访问修饰符)来修饰类中的字段和方法的作用范围,是目前实现狭义封装的一种方式。- 创建完一个类后,类中的字段使用 private 修饰,类中的方法使用 public 修饰;
- 为类中用 private 修饰的字段添加一组方法,以保证既能保护类中的字段不被任何赋值修改,又可在外界必须访问这些字段时,提供一种间接访问方式;
- 说明:这组间接的访问方法叫做:Get和Set方法。
标准属性
基本语法:1
2
3
4
5[访问修饰符] 数据类型 属性名
{
get { return 字段名; }
set { 字段名 = value ; }
}注意事项:
访问修饰符,一般都是使用 public
数据类型,就是当前操作的字段的类型
属性名,就是当前操作的字段名(使用Pascal命名法)。标准属性基本特点:
一个字段通常对应一个属性,属性的类型应与当前字段定义时的类型保持一致;
一个属性中包含一组方法 , get用于获取字段值 , set 用于为字段赋值,赋值时系统存在一个隐式变量,为value 在为字段赋值时,业务逻辑处理的代码,也是放在set中的;
属性本身不保存任何数据,访问字段为字段赋值等操作,看似操作的是属性,实质对数据的访问设置还是对字段的操作,且是由这两个方法实现;
标准属性,可设置只读 | 只写属性 ,只读权限时只保留get 方法即可;只写权限时只保留 set 方法即可;即可读又可写权限时 get 和 set 都要保留。
对象.属性 = xxx 时会将xxx自动传给隐式变量value set中可判断value的取值范围,满足要求再传给属性字段自动属性
当属性(又叫属性访问器)中不需要任何其他逻辑时(即不需要在set方法中添加任何业务代码)使用自动属性可以更加简洁。
自动属性本质就是一个字段两个方法。
语法:[访问修饰符] 数据类型 属性名 { get ; set ; }自动属性特点:
自动属性可利用编译器自动生成,以简化代码的编写注:代码中输入prop,按两下Tab键即可自动生成;
自动属性只能成对出现,即:不能只有一个get或一个set,也就是,自动属性不支持设置 只读 | 只写 操作;
自动属性不支持在 set 中添加业务逻辑代码;
编译器在生成自动属性时,会自动添加一个私有的字段,我们在写时,不用再自己声明私有字段,只需要直接添加属性即可。1
2
3
4
5
6
7
8
9public int name{
get;
set;
}
//等价于
private int name;
public int Name{
get;set;
}
继承性
单继承,即:一个子类只能有一个直接父类(继承的单层性);
编译器是先进入到父类中,调用父类无参数的构造方法,如果父类没有无参数构造方法,编译器会自动为父类添加无参数,执行完父类无参数后,再执行子类自己的构造方法
如果父类有其它形式构造方法,但是没有无参数的构造方法,此时程序会报错。
- base
访问父类中的同名方法,适合于子类中存在与父类相同签名的方法时;
访问父类的构造方法,在子类构造方法的小括号后面使用 : base( 参数值列表 ) 表示访问父类的构造方法;
子类构造方法小括号后面默认省略 :base()
多态性
父类变量,创建子类对象
基本语法:
父类 变量名 = new 子类(参数列表)
向上转型
在执行期间判断对象的类型,决定执行子类还是父类的方法的机制称之为动态绑定。
当子类和父类都有相同的方法时,调用子类自己的方法;
当子类没有该方法时,调用父类的方法;
当子类和父类都没有调用的方法时,程序编译报错。
应用:
- 多态在数组方面的应用
多态数组
创建Car类的数组,可放不同子类的对象,并override不同子类的方法,自动识别 多态特性作用于方法的参数上
方法参数多态
定义方法的参数类型时,要求参数既可以接收多种子类型,此时就可以将参数的类型定义为父类型,而运行时会根据传递过来的参数类型具体匹配。多态特性作用于方法的返回值上
Static
- 静态成员变量
静态成员变量属于类,类被加载时初始化,且只有一份。
特点:存在优先于对象,被所有对象所共享,常驻内存。 - 静态构造函数
初始化类的静态数据成员。
仅在类被加载时执行一次。
不允许使用访问修饰符。 - 静态方法
通过引用调用实例方法时,会隐式的传递对象引用,以便在方法内部可以正确访问该对象成员变量。
通过类名调用静态方法时,因为没有具体对象,所以在static方法中不能访问实例成员。 静态类
不能实例化,只能包含静态成员。
静态类不能被继承,但是静态方法、属性都可以被继承。利:单独空间存储,所有对象共享,可直接被类名调用。
弊:静态方法中只能访问静态成员,共享数据被多个对象访问会出现并发。- 适用场合:
- 所有对象需要共享的数据。
- 在没有对象前就要访问成员。
- 工具类适合做静态类(常用,不需要过多数据)。
struct
与类语法相似,都可以包含数据成员和方法成员。但结构属于值类型,类属于引用类型。
适用表示点、颜色等轻量级对象。如创建存储1000个点的数组,如果使用类,将为每个对象分配更多内存,使用结构可以节约资源。
除非字段被声明为 const 或 static,否则无法初始化。
结构不能继承,但可以实现接口。
结构总会包含无参数构造函数。
构造函数中必须初始化所有字段。
结构不能包含显式的无参数构造函数
集合
可对集合中的元素进行增删改查操作,作用都是原集合,而不会产生新的集合。
- ArrayList
底层就是一个可动态扩展的数组;
提供了用于在集合中添加、删除或查找项的方法;
ArrayList 集合不支持泛型(即:可放任意类型的数据);
使用 ArrayList 集合之前,应先导入命名命名空间:using System.Collections ; - List
类似于ArrayList集合,同样也提供了很多用于在集合中添加、删除或查找项的方法;提供了比ArrayList更多操作集合的方法
List 集合支持泛型;
List 集合默认的命名命名空间:using System.Collections.Generic; - Dictionary
内存分配
- 类型分配
值类型:存储数据本身。声明在栈中,数据存储在栈中。
引用类型:存储数据的引用(内存地址) 声明在栈中,数据存储在堆中,栈中存储该数据的引用。 - 内存分配
程序运行时,CLR将申请的内存空间从逻辑上进行划分。- 栈区:
— 空间小(1MB),读取速度快。
— 用于存储正在执行的方法,分配的空间叫做栈帧。栈帧中存储方法的参数以及变量等数据。方法执行完毕后,对应的栈帧将被清除。 - 堆区:
— 空间大,读取速度慢。
— 用于存储引用类型的数据。
- 栈区:
GC(Garbage Collection)是CLR中一种针对托管堆自动回收释放内存的服务。
GC线程从栈中的引用开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,那么就认为这块内存不再使用了,即为可回收的。使用比较运算符比较值类型时,对比的是存储的数值。
比较引用类型时,对比的是引用的地址而不是数据。