C#基础知识点总结
-
属性:封装了 一部分对象状态的函数成员
-
事件:简化对象状态转化处理的函数成员
-
C#不支持类的多继承(与C++不同),但可同时实现多个接口
-
C#是一种类型安全的语言,即类型只能通过定义的协议进行交互,从而保证内部类型的一致化。
-
C#支持静态类型化,在编译时会执行静态类型安全性检查
-
C#依靠运行时环境来自动的内存管理(不同于C/C++等语言,优点:程序员不需要显式的释放对象分配的内存资源避免了因错误使用指针造成的错误 缺点:无法向非托管语言C/C++对系统进行低级控制,完全按照自己的想法管理内存)
-
C#编译器可以把一系列的.cs文件编译为程序集,程序集是.Net中最小的打包和部署单元,程序集可以是一个可执行文件.exe,也可以是一个类库文件.dll(相当于一个没有入口的.exe)
-
C#编译器的名称叫csc.exe在命令行调用CSC的命令如下:
生成应用程序(.exe)
csc filename.cs
生成类库文件(.dll)
Csc /target:libarary filename.cs
-
标识符:程序员为类、方法、字段、变量等选择的名字
标识符是由字母/下划线开头的Unicode字符组成的,C#标识符是区分大小写的,通常约定参数、局部变量和私有字段应该由小写字母开头,而其他标识符则应该由大写字母开头
-
关键字:又称保留字,为编译器预留的名称,当使用关键字时需要在其前面加上@符号,如string @string
注意:@不是标识符的一部分,@string和string表示的是同一个变量
-
C#预定义类型:数值类型、字符串类型、bool类型
-
C#中的所有类型都是类型的实例,值表示存储位置的符号,变量表示它包含的值可能会不断变化,常量则表示里面的值总是表示同一个值
-
类型的隐式转换:编译器能保证转换一定能够成功
转换过程中不会丢失信息
类型的显式转换条件与上面的相对
-
C#中的类型可以分为:①值类型 ②引用类型③参数类型④指针类型
-
值类型:
数值类型、bool类型、char类型、bool类型、enum类型、struct
引用类型:
字符串、接口、类、委托、数组
引用类型和值类型的最大不同在于内存的分配方式:
值类型:通常在当前执行线程的堆栈(stack)上分配内存
引用类型:通常在托管堆(manage heap)上分配内存
-
值类型的变量或者常量的内容仅仅是一个值,值类型复制时复制的是这个值本身,引用类型又对象和对象的引用两部分组成,引用类型的变量或常量里面存的是一个包含值的对象的引用,复制时复制的仅仅是这个引用
当一个引用类型被赋值为null时表示它不指向任何一个对象。
-
在C#中非零值除以零是无穷大,零除以零是NaN
无穷大减去无穷大NaN
各种int
Int16àshort(16位)
Int32àint(32位)
Int64àlong(64位)
-
float单精度类型,精度为5~6位(超出部分按照四舍五入规则舍去),占4个字节的存储空间
double双精度类型,精度为15~16位((超出部分按照四舍五入规则舍去)),占8个字节的存储空间(声明的小数默认都是double类型)
float和double内部都是基于2进制表示的,只有基于2表示的数值才能被精确的表示
decimal(多用于金融的数据处理方面)内部是基于10表示,可以精确的表示大多数小数(但处理速度要比处理float和double慢)
-
C#中bool类型能表示True和False,尽管这只需要1位的存储空间,单运行时却要使用1个字节的空间(因为字节是处理器和运行时能有效处理的最小单位),为了避免不必要的空间浪费,.Net Framework的System。Collections命名空间下有专门的BitArray类,每个布尔值占1位的空间。
-
栈是存储参数和局部变量的地方,堆是对象残留的内存块,堆上可以存储静态字段、常量、
-
C#中的参数传递:
>1、值传递(默认的传递参数的方式):每次传递的是原值的副本,改变副本并不会影响原值
>2引用传递:相当于给原变量的存储空间起了一个别名,原值和复制后的变量访问的是同一块内存,通过改变副本会改变原变量的值
注意:无论参数是值类型还是引用类型都可以按照引用传递
引用传参有可分为两种:ref和out
Ref:在声明和调用时都要添加ref关键字
Out 和 ref类似,除了:
ref必须在使用前给变量赋值,而out不必,但out必须在函数结束前为其赋值
-
值是变量或常量表示的存储位置,变量是表示存储位置的符号,它包含的值可能发生变化,常量包含的自初始化后不再发生变化。
-
类型转换
隐式转换发生条件:
编译器能保证转换总是能成功
没有信息在转换过程中丢失
显式转换发生条件:
编译器不能保证转换总是能成功
信息在转换过程有可能发生
-
明确赋值
<1> 局部变量在读取钱必须明确赋值
<2> 当调用方法时必须提供函数的参数
<3>其它的所有变量(像字段和数组元素)都自动在运行时别初始化(使用其类型的默认值)
所有引用类型的默认值:null
所有数值和枚举类型的默认值:0
字符类型默认值:'\0'
布尔类型默认值: False
能够使用default关键字来获取其关键值
-
C#中的属性
当使用自动属性时,编译器会在后台产生私有字段,该字段名称由编译器生成,切不能被引用,如何希望属性是只读的,可以将set访问器设置为private
C#中的属性访问器在系统内部被编译为get_xxx和set_XXX方法
-
索引器
索引器为访问类或结构体中的列表或字典提供了自然的访问接口,索引器和属性很相似,但索引器通过索引值而非属性名访问数据元素,简化了对类中列表和字典的访问。
要实现索引器,首先定义一个名为this的属性,将参数定义放在一对方括号中,
Public string this[int index]{
Get{}
Set{}
}
索引器在系统内部被编译为get_Item()和set_Item()的方法
-
C#中new 和virtual的不同:
当CLR遇到一个virtual 方法时,它会调用派生得最远的实现并重写virtual成员的实现。
如果重写一个方法时没有加上"override"关键字,则会报告一条警告消息。这时,可以加上"new"来消除警告。告知编译器和其它编程人员,这个成员的隐藏不是无意的。
从C#的角度来看,new关键字的主要作用在于:移除编译器的警告。
new在基类面前隐藏了派生类的重新声明的成员。在这种情况下,不是调用派生得最远的成员。相反,基类的成员会搜索继承链,找到使用了new关键字的那个成员之前的成员,然后调用该成员。如果继承链中只有两个类,就会使用基类中的成员,感觉就像没有在派生类中重写那个成员。
-
C#构造方法
28.1、C#编译器自动为没有显式提供构造方法的类生成构造函数,如果显式指定构造函数将不再生成这个无参构造函数,对于结构体来说,这个无参构造函数是必须的,不能自己定义,其作用是用默认值来初始化每个字段。
28.2、类或结构体中的字段按照初始化顺序在构造方法执行执行字段的初始化
28.3 构造函数的重载
在构造函数中可以通过this关键字调用所在类的其它构造函数,减少代码重复,此时被调用的构造函数先执行
Eg:
Public class test{
Public test(string test){
}
Public test(string test,int test) :this(string test){
}
}
关键字base和关键字this类似,它有两个重要的目的:
从子类访问重载的基类方法成员
调用基类的构造函数
28.4 构造方法和字段的初始化顺序
(1) 从子类到基类 :初始化字段à指定被调用基类的构造方法中的变量
(2)从基类到子类:构造方法体自行
-
重载和解析:
当重载被调用时,类型最明确的优先匹配,具体调用哪个重载是在编译时确定,而不是在运行时决定
-
装箱和拆箱
装箱:把数值类型实例转换为引用类型实例
拆箱:把引用类型实例转换为数值类型实例
装箱和拆箱的本质是复制,装箱是把值类型的实例复制到新的引用类型中,拆箱是把引用类型中的值复制到值类型的实例中。
-
GetType()方法和TypeOf运算符
C#的所有类型在编译和运行时期都维护一个System.Type类的实例,有两个方法可以获得System.Type对象
-
在类的实例上调用GetType()方法
-
在类名上使用TypeOf运算符
两者不同在于,GetType在运行时赋值,而TypeOf运算符在编译时赋值
-
访问权限修饰符
-
public:完全访问权限 ,枚举类型成员或接口隐含的访问权限
-
internal:尽可访问程序集和友元程序集,非嵌套类型(比如类)的默认访问权限
-
private:仅在类型内可见,类和结构体成员的默认访问权限
-
protected:仅在类中和子类中可见
-
接口
-
接口的显式实现
当 实现多个接口时,有时成员标识会有冲突,这时可以显式实现接口来 解决冲突
Public Interface ITest{
Void DoSomething();
}
Public class Test:ITest{
ITest.DoSomething(){}//接口的显式实现
}
❈注意:调用显式实现的成员的唯一方法是将对象转换为相应的接口
Test t = new Test();
(ITest)t.DoSomething();
-
虚方法实现接口成员
默认情况下,接口成员的实现都是隐式定义为sealed。为了能重载,必须在基类中标识为Virtual或abstract
Public class Test:ITest{
Public virtual void DoSomething(){}
}
❈注意:显式实现的接口成员不能标识为virtual