都发C++了,C#也发一下吧,C#人柱力是酱紫的喵
目录
1.GC回收流程
GC是CLR(公共语言运行时)的重要组成部分,用于进行自动内存管理,它将所有引用类型放在托管堆上,值类型放在栈上,并把资源分为托管资源:如实例和数组和非托管资源:如数据库和文件读写口。
过程:
1.分代回收:GC将对象的使用等级分为0,1,2三个等级,新创建的对象为0级,每躲过若干次回收,对象将得到升级,低等级的资源先回收。
2.标记和清除:GC工作时,会从根对象进行延伸标记,未标记的将被回收。
3.终结器重标记和对象压缩:在进行资源回收前:若对象含有终结器:则调用终结器决定是否回收对象,之后在每个对象完成回收时将对象移走,避免产生内存碎片。
4.优化:
(1)LOF(引用局部性):GC进行内存分配时总是将对象内存分配到里内存位置近的位置
(2)LOH(大对象堆):对于大于一定值的对象,GC将其放置到大对象堆,不进行压缩。
2.值类型和引用类型(装箱和拆箱)
装箱和拆箱
装箱:将值类型转换为引用类型时:将值类型数据复制到引用类型对应的GC托管堆中,并返回该位置引用的过程,该过程通常是隐式的。
拆箱:将引用类型转换为值类型时:GC检测类型是否兼容后:从GC托管堆移动到GC栈赋给值类型的过程,该过程通常是显示的。
拆箱或者装箱的两种类型必须具有继承关系 int和string转换不发生拆装箱
装箱和拆箱会影响程序的运行效率,下面的string用StringBuilder来做中间人就是这个原因
两者的区别:值类型的值存储在栈上,引用类型的地址存储在GC栈上,值存储在GC托管堆里
注意:
当值类型进行传递时,无论后者怎么变都不改变值的本质,如
int a = 10;int b= a;b=20;此时a还是10
当引用类型进行传递时,只要二者之一发生变化则全体发送变化,因为传递的是堆空间,如:
int[] a = new int[1]{1}; int[] b= a;b[0]=10;则a[0]也变化为10
但是需要注意但是:
int[] a = new int[1]{1}; int[] b= new int[1]{a[0]};b[0]=10;此时不会导致a[0]发送变化,因为a[0]是int类型,即值类型。
此外string类型具有不变性,即string a = “1”;string b = a;b=”22”;不会改变a
3.委托,事件和lambda表达式
委托是C#一种特殊的类,事件是委托的一个特殊成员,lambda表达式是一种匿名函数。
4.CTS,CLS和CLR
CTS,通用语言系统,.NET通过CTS提供的公共类型转化成.NET自己的类型。
CLS,通用语言规范,.NET根据CLS的语言规范,将不同语言翻译为.NET的语言规范。
CLR:公共语言运行库,.NET通过CLR就完成运行。
5.C#的结构体和类的区别
类是引用类型,放在堆空间中,可继承,可当接口,结构体是值类型,放在栈空间。
6.?在C#的作用
?是C#中一个特殊比较特殊的定义符,除了三元表达式外:
对于类型?如:int?:能够将值类型变量装箱为引用类型实现
对于变量? 如:eventname?:能够变量检测是否为空。
7.C#的三种特殊参数符有什么区别
ref能够将实参像引用类型一样使用,但是使用ref的实参不能为空。
out能够将实参视作返回值,但是在返回之前必须被赋值。
params只能作为函数的最后一个参数,且参数必须是一维数组,传入时数量不限,使用时:params[i]代表传入的第i个参数。
8.C#多态的实现过程中:重载和重写的区别
重写是同一函数名拥有相同参数和返回值的实现,其具有覆盖原函数的特点,是面向对象的概念。
重载是同一函数名不同参数和返回值的实现,其特点是多个同名函数共存,能够反应多种需求,是面向过程的概念。
9.C#的内存分区
栈区:存储值类型和引用类型的指针。
堆区:存储引用类型,受GC管理。
全局区/静态区:储存全局变量和静态变量,在程序结束时回收。
常量区:存储常量,只能读,不能修改。
代码区:存储代码,只能执行,不能修改。
10.C#的实例化调用顺序
实例化时:
静态成员初始化->静态成员构造函数->普通成员初始化->普通成员构造函数->静态构造函数->构造函数
即:静态的先于普通的,默认的先于手动的。
11.静态构造函数和构造函数
静态构造函数是C#的一种特殊的构造函数,通常用于初始化类的静态成员,仅在类的首次实例化时调用。
12.static
在C#中:static的主要作用是:扩大类成员的作用域,在每个类的整个生命周期中唯一,属于类本身,而不是类的实例,能够通过类直接调用,并且C#是没有全局变量的概念的。
静态类:若一个类是静态的:则它被定义为static,他的成员必须是静态的,他本身也不允许被实例化。
13.C#的get,set和索引器的底层逻辑
get,set是C#的属性的访问器,定义属性的读取和写入行为,索引器则是为类提供一个类似数组的访问呢功能,其参数不限类型和数量,但是通常在C#的每个类中仅存在一个索引器,即this索引器。
14.C#的部分类和密封类
若这个类加上partial关键字,部分类必须的所有同名类都要加上partial关键字,他们被视为一个类,且要求在同一命名空间。
若这个类加上sealed关键字,则这个类无法被继承,不过可以继承别人。
15.抽象类和接口的区别
抽象类:abstract关键字修饰的类和普通类一样一个类仅能继承一个抽象类,只有抽象类能够持有带abstract的抽象方法,对成员的类别和访问域没有太多限制。
接口:interface关键字声明的一种类,定义时不需要class关键字,成员只能声明,不能实现,且成员不能声明自己的访问域,只能公开,此外:字段不允许在接口中出现(属性可以)。
16.虚函数和抽象函数
虚函数:virtual修饰的函数,和C++一样,父级可实现,子级选择性重写
abstract型抽象函数:abstract修饰的函数,和C++一样,父类不可实现,非抽象子类必须重写,该类别的抽象函数只能在抽象类中声明。
接口型抽象函数:和abstract型抽象函数一样,但是不需要abstract关键字。
17.null和Empty()的区别
当一个变量被声明为null时:将不会被分配内存空间,但是声明为Empty()的类将被赋予类型的默认值。
18.string和StringBuilder的区别
两者都是引用类型,但是
C#的string具有不可变性,一旦创建内容就无法改变,对其进行增删改查都需要从堆空间中进行重新处理,但是他是线程安全的。
StringBuilder不具备不可变性,且在创建时就预留了一定的扩展空间,因此能够快速进行增删改查操作,但是他是线程不安全的。
19.拓展函数
拓展函数是C#的一种特殊的函数,能够拓展现有类型或者默认类型的使用范围和功能。
但是:扩展函数必须在静态类中,其格式为:
访问域 static 返回值 Name(this 拓展类型 name,参数){实现}
20.特性
特性是C#为C#程序实体添加元数据的一种机制,能够被编译器识别用于执行一些特殊操作又或者在运行时通过反射进行检查,其本质是类,能够为在目标实体被写入.dll文件时附加一些元数据。
常用的特性有:
1.[Obsolete]:废弃的,被标注为废弃的实体在调用时会发出警告。
2.[Caller]系列:如[CallerLineNumber],[CallerFilePath],[CallerMemberName]:能够将目标的行数,文件路径,文件名等等录入到实体中。
3.[Serializable]:使得程序实体被序列化,能够存储成文件或者被读取。
4.[WebMethod]:使得程序实体可以被Web访问,
21.反射
反射是指在程序运行时试图访问程序实体的元数据的一种行为,允许程序在运行时完成类型检查并进行动态的创建和调用,通过System.Reflection实现,具有高解耦,可拓展,跨语言,动态等等诸多优点和高开销,封装爆破(即能够访问类的私有成员)等缺点。
22.byte类型
byte:字节类型,一个字节8个bit,一个汉字,通常是两个字节,因此把汉字赋给一个字节时会报错,属于无符号整数类型,范围是0-255,即byte=256也会报错。
23.const和readonly
在C#中,如果一个变量被声明为const,那么:这个变量将默认是静态的(不需要static符,但是和static一样的效果),且const仅能在变量左侧(也就是没有定向),同时:在编译时完成初始化,和static不同的是:const关键字允许在普通函数中使用。
而readonly则仅仅是将变量声明为只读,不做其他限制。
24.强类型和弱类型
C#是一门强类型语言,即变量类型必须声明,但是包含了极少部分的弱类型,如能够表示巨大数额的dynamic是弱类型,在赋值时不进行类型检查,但是在运行时类型不对会报错
25.as和is的区别
as是类型转换符:如 int a = b as int;,转换失败返回null,is是类型判别符,如 b is int,返回true或false,as的效率要更高,因为is要判定是否是指定类型外还要判空。