C#高级编程 Notes
Part 1 C# 语言
Core C#
常量总是静态的。
byte
类型默认无符号,有符号的叫sbyte
。
decimal
类型不是基本类型,在计算时候会有性能损失。
string
(System.String
):引用类型,对象分配在堆上。字符串不可变,修改一个字符串会创建一个新的string对象,原来字符串不变。
object
(System.Object
)。
case
子句必须包含break
语句,除非子句为空。
属性和方法的使用
- 客户端应能读取它的值,最好不要使用只写属性。
- 读取值不应花太长的时间。
- 读取值不应有任何明显的和不希望的负面效应。
- 可以按照任何顺序设置属性。
- 顺序读取属性也应有相同的效果。
字段应总是私有的,某些情况可以把常量或只读字段设置为公有。
对象和类型
重载方法的限制
- 方法不能仅在返回类型上有区别。
- 方法不能仅根据参数是声明为
ref
或out
来区分。
在何处内联代码完全由CLR决定(与C++不同)。
私有构造函数的作用
- 类仅用作某些静态成员或属性的容器,因此永远不会实例化它。
- 希望类仅通过调用某个静态成员函数来实例化(对象实例化的类工厂方法)。
静态构造函数
- 无参数,无访问修饰符,只执行一次,在代码引用类之前调用它。通常在第一次调用类的任何成员之前执行静态构造函数。
- 类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。
结构 struct
:值类型,存储在栈或者内联(如果它们是存储在堆中的另一个对象的一部分),new
只是调用相应构造函数,并不分配堆中内存。
- 不支持继承,可以继承接口。
- 编译器总是提供一个无参构造函数,不允许自定义无参构造函数。
- 可以指定字段如何在内存中布局。
- 字段默认私有(与C++不同)。
弱引用 WeakReference
。
静态类 static class
。
继承
除非显式指定,否则函数就不是虚拟的(在Java中所有的函数都是虚拟的)。
泛型
泛型的好处
- 性能。不再进行装箱和拆箱操作。
- 类型安全。
- 允许更好地重用二进制代码,可以在一种语言中定义,在任何其他.NET语言中使用。
泛型类的静态成员只能在类的一个实例中共享。
运算符和类型转换
C#要求所有的运算符重载都声明为public static
(与C++不同);某些运算符应该成对重载。
强制类型转换:public static implicit operator int (A a) { ... }
LINQ
推迟查询:迭代在查询定义时不会进行,而是在执行每个foreach
语句时进行。
异步编程
/* Refer to CLR via C#. */
内存管理
后台内存管理
值数据类型:栈存储不是对象成员的值数据类型;在调用一个方法时,也使用栈存储传递给方法的所有参数的副本。
引用数据类型:托管堆,在垃圾回收器的控制下工作。
垃圾回收
- 垃圾回收器的压缩操作是托管堆与非托管的旧堆的区别所在。使用托管的堆只需要读取堆指针的值,不需遍历地址的链表来查找一个地方来放置新数据。因此在.NET下实例化对象要快得多。访问也较快(对象压缩到相同内存区域,页面交换少)。MS相信GC压缩、修改移动对象的引用值的开销是值得的。
- 可以调用
System.GC.Collect()
强迫运行回收器(不保证删除所有未引用的对象)。 - 大对象堆。
- 垃圾回收的负载均衡。
释放非托管资源
非托管资源:文件句柄、网络连接、数据库连接等。
托管类在封装对非托管资源的直接或间接引用时,需要制定专门的规则,确保非托管的资源在回收类的一个实例时释放。
释放非托管资源的两种机制
1) 声明析构函数或终结器,作为类的一个成员
1 | class MyClass |
C#与C++在析构上的区别:在销毁C++对象时析构函数会立即执行。由于C#垃圾回收器的工作方式,无法确定C#对象的析构函数何时执行。
2) 在类中实现System.IDisposable
接口(推荐)
Dispose()
方法显式释放由对象直接使用的所有非托管资源,并在所有也实现IDisposable
接口的封装对象上调用Dispose()
方法,为何时释放非托管资源提供了精确的控制。
1 | // V1 |
实现IDisposable
接口+使用析构函数
1 | public class ResourceHolder : IDisposable |