c#常用的基础概念
Q1 静态变量和非静态变量的区别。
A1 静态变量: 静态变量使用 static 修饰符进行声明,在所属类被装载时创建,通过类进行访问,所属类的所有实例的同一静态变量都是同一个值
非静态变量: 不带有 static 修饰符声明的变量称做非静态变量,在类被实例化时创建,通过对象进行访问,同一个类的不同实例的同一非静态变量可以是不同的值
Q2 const 和 static readonly 的区别
A2 const 修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序。 而用static readonly 修饰符声明的依旧是变量,只是具有和常量类似的使用方法,比如通过类进行访问、初始化后不可以修改。但与const不同的是它在运行时初始化。
Q3 extern 何解
A3 extern修饰符用来声明程序集外部实现的成员函数。经常用于系统API函数的调用(通过DllImport)。不过注意的是,它和DllImport一起使用的时候都要使用static修饰符。 也可以用于对同一个程序集不同版本组件的调用(extern声明别名), 它不能与abstract 修饰符同时使用。
Q4 abstract
A4 abstract可以修饰类,方法,属性,事件和索引指示器,表示其位抽象成员。它不可以与static, virtual,override一起使用。声明为abstract成员可以不包括任何实现代码,但只要类中有未实现的抽象成员,则此类不可以初始化。
Q5 internal
A5 internal修饰符可以用于类型或成员,它限定此声明的类型或成员只能在同一个程序集内访问。接口的成员不能使用internal修饰符。
Q6 sealed
A6 sealed表示密封。使用于类时,表示该类不能再被继承,不能和abstract同时使用。因为他们在修饰符含义上相互排斥。 用于方法和属性时,表示该方法或者属性不能再被继承,必须和override关键字一起使用,因为使用sealed修饰符的方法或者属性肯定是基类中的相应的虚成员。 通常使用第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱。恰当的利用sealed可以提高一定的运行效率,因为不用考虑继承类会重写该成员。
Q7 override 和 overload的区别
A7 override 表示重写,用于继承类对基类中虚成员的实现。 而overload 表示重载,用于同一个类中同名方法不同参数(包括类型不同和个数不同)的实现。
Q8 索引指示器
A8 实现索引指示器(indexer)的类可以像数组那样使用其实例后的对象,但与数组不同的是索引指示器的参数类型不仅限于int。 其本质上是一个含有参数的属性。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Q9 new的作用
A9 new 修饰符和new 操作符是两个概念。new 修饰符用于声明类或者类的成员,表示隐藏了基类中的同名成员。而 new 操作符用于实例化一个类型。 new 修饰符只能用于继承类,一般弥补基类的设计不足。 new修饰符和override修饰符不可用在同一个成员上,因为两个修饰符意义上相互排斥。
Q10 this关键字
A10 this是一个保留字,仅限于构造函数和方法成员中使用。在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法成员中出现表示对调用该方法的对象的引用,在结构的构造函数中出现表示对正构造的结构的引用,在结构的方法中出现表示对调用该方法的结构的应用。
this 保留字不能用于静态成员的实现里,因为这是对象或结构并没有实例化。在C#中, this实际上时一个常量,所以不能使用 this++ 。它一般用于限定同名的隐藏成员,将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身。
Q11 可以使用抽象函数重写基类中的虚函数吗
A11 Yes。eg:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Q12 密封类可以用虚函数吗?
A12 可以。 基类中的虚函数将隐式的转化为非虚函数。 但密封了本身不能在声明虚函数。
Q13 如果基类中的虚属性只有一个属性访问器,那么继承类中有几个?如果基类中有get 和 set两个呢?
A13 如果基类只有一个的话,继承类重写该属性后也只有一个。 如果基类有两个,则继承类可以有一个或者有两个。
Q14 abstract 可以与virtual 一起使用吗? override呢?
A14 abstract 不能与 static、 virtual 、override 一起使用。
Q15 接口可以包含哪些成员
A15 接口可以包含属性、方法、索引指示器和事件, 但不能保护常量、域、操作符、构造函数、析构函数以及任何静态成员。
Q16 类和结构的区别
A16 类是引用类型,在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存,并且有构造函数和析构函数,可以继承和被继承。
结构式值类型,在栈上分配(栈的反问速度快,但资源有限)。结构的赋值将产生新的对象。结构没有构造函数和析构函数,构造函数可以添加。结构不可以继承自另一个结构和被继承, 但它可以继承自接口。
Q17 接口的多继承会有啥缺陷
A17 C#中的接口与类不同,可以使用多继承,既一个子接口可以有多个父接口。但如果两个父成员有相同的成员,就产生了二义性,这是实现最后使用显示的声明。
Q18 接口和抽象类的区别
A18 抽象类可以包含功能的定义和实现,接口只能包含功能定义。 抽象类是从一系列相关对象中抽象出来的概念,因此反映了事物的内部共性;接口是为了满足外部调用而定义的一个约定,反映的是事物外部的特性。分析对象,提炼内部共性形成抽象类,用以表示对象本质,既“是什么”, 为外部提供调用或者功能需要扩充时优先使用接口。
Q19 如何释放非托管资源?
A19 .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资源进行释放,这时我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象。最简单的办法,可以通过实现protected void Finalize()(析构函数会在编译时变成这个东东)来释放非托管资源,因为GC在释放对象时会检查该对象是否实现了 Finalize() 方法,如果是则调用它。但,据说这样会降低效率。。。 有一种更好的,那就是通过实现一个接口显式的提供给客户调用端手工释放对象的方法,而不是傻傻的等着GC来释放我们的对象(何况效率又那么低。 System 命名空间内有一个 IDisposable 接口,拿来做这事非常合适,就省得我们自己再声明一个接口了。另外补充一句,这种实现并不一定要使用了非托管资源后才用,如果你设计的类会在运行时有大些的实例(象 GIS 中的Geometry),为了优化程序性能,你也可以通过实现该接口让客户调用端在确认不需要这些对象时手工释放它们。
Q20 P/Invoke是什么
A20 在受控代码与非受控代码进行交互时会产生一个事务(transition) ,这通常发生在使用平台调用服务(Platform Invocation Services),即P/Invoke 如调用系统的API 或与 COM 对象打交道,通过 System.Runtime.InteropServices 命名空间。虽然使用 Interop 非常方便,但据估计每次调用事务都要执行 10 到 40 条指令,算起来开销也不少,所以我们要尽量少调用事务。 如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则。
Q21 explicit 和 implicit 的含义?
A21 explicit 和 implicit 属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换。explicti 表示显式转换,如从 A -> B 必须进行强制类型转换(B = (B)A)。implicit 表示隐式转换,如从 B -> A 只需直接赋值(A = B)。隐式转换可以让我们的代码看上去更漂亮、更简洁易懂,所以最好多使用 implicit 运算符。不过!如果对象本身在转换时会损失一些信息(如精度),那么我们只能使用 explicit 运算符,以便在编译期就能警告客户调用端
Q22 params 有什么用?
A22 params 关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变的能力。它在只能出现一次并且不能在其后再有参数定义,之前可以。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)