前言:这是自己的第一篇博客,纪念一下,下面所有的内容出自《你必须知道的.NET》系列博客,内容比较散,作用在于提醒自己温故而知新。
再谈谈自己对c#语言的认知,众所周知c#在IT行业并不火,但本人认为c#却很实用,其与c++交互,com技术混合编程都很方便。特别是在工控领域,目前c#应用程序比较受欢迎。自己也打算在这个领域深耕。以后会利用空余时间多多积累和学习。也希望自己以后多写一写博客,总结一下自己学习所得与心得。2019.0216.
CLR管理内存的区域,主要有三块,分别为:1、线程的堆栈,用于分配值类型实例
2、GC堆,用于分配小对象实例
3、LOH(Large Object Heap)堆,用于分配大对象实例
连续分配的对象在内存中一定是连续的
IL图示
类型层次图:
总结起来,.NET的自动内存管理,主要包括以下几个方面:
l 对象创建时的内存分配。
l 垃圾回收。
l 非托管资源释放。
在进入实际的内存分配分析之前,有必要对几个基本概念做个交代,以便更好地在接下来的分析中展开讨论。
TypeHandle,类型句柄,指向对应实例的方法表,每个对象创建时都包含该附加成员,并且占用4个字节的内存空间。我们知道,每个类型都对应于一个方法表,方法表创建于编译时,主要包含了类型的特征信息、实现的接口数目、方法表的slot数目等。
SyncBlockIndex,用于线程同步,每个对象创建时也包含该附加成员,它指向一块被称为Synchronization Block的内存块,用于管理对象同步,同样占用4个字节的内存空间。
NextObjPtr,由托管堆维护的一个指针,用于标识下一个新建对象分配时在托管堆中所处的位置。CLR初始化时,NextObjPtr位于托管堆的基地址。
常见的非托管资源包括数据库链接、文件句柄、网络链接、互斥体、COM对象、套接字、位图和GDI+对象等
5.4.2 性能条款 ¡
Item1:推荐以Dispose模式来代替Finalize方式。
Item2:选择合适的垃圾收集器:工作站GC和服务期GC
Item3:在适当的情况下对对象实现弱引用
在.NET中,WeakReference类用于表示弱引用,通过其Target属性来表示要追踪的对象,通过其值赋给变量来创建目标对象的强引用,例如:
public void WeakRef()
{
MyClass mc = new MyClass();
//创建弱引用
WeakReference wr = new WeakReference(mc);
//移除强引用
mc = null;
if (wr.IsAlive)
{
//弱引用转换为强引用,对象可以再次使用
mc = wr.Target as MyClass;
}
else
{
//对象已经被回收,重新创建
mc = new MyClass();
}
}
Item4:尽可能以using来执行资源清理。
Item5:推荐使用泛型集合来代替非泛型集合。
Item6:初始化时最好为集合对象指定大小。
Item7:特定类型的Array性能优于ArrayList。
Item8:字符串驻留机制,是CLR为String类型实现的特殊设计。
Item9:合理使用System.String和System.Text.StringBuilder。
Item10:尽量在子类中重写ToString方法。
¡ Item11:其他推荐的字符串操作。 字符串比较,常常习惯的做法是: public bool StringCompare(string str1, string str2)
{ return str1 == str2; } 而较好的实现应该是:public int StringCompare(string str1, string str2) { return String.Compare(str1, str2); }
Item12:for和foreach的选择。
Item13:以多线程处理应对系统设计。
Item14:尽可能少地抛出异常,禁止将异常处理放在循环内。
Item15:捕获异常时,catch块中尽量指定具体的异常筛选器,多个catch块应该保证异常由特殊到一般的排列顺序
Item16:struct和class的性能比较。
Item17:以is/as模式进行类型兼容性检查。
Item18:const和static readonly的权衡。
const是编译时常量,readonly是运行时常量,所以const高效,readonly灵活。在实际的应用中,推荐以static readonly来代替const,以解决const可能引起的程序集引用不一致问题,还有带来的较多灵活性控制。
Item19:尽量避免不当的装箱和拆箱,选择合适的代替方案。
Item20:尽量使用一维零基数组。
Item21:以FxCop工具,检查你的代码。 FxCop是微软开发的一个针对.NET托管环境的代码分析工具,如图5-11所示,可以帮助我们检查分析现存托管程序在设计、本地化、命名规范、性能和安全性几个方面是否规范。
Dispose方法用于清理对象封装的非托管资源,而不是释放对象的内存,对象的内存依然由垃圾回收器控制。
抽象类和接口的比较:
相同点
都不能被直接实例化,都可以通过继承实现其抽象方法。
都是面向抽象编程的技术基础,实现了诸多的设计模式。
不同点
接口支持多继承;抽象类不能实现多继承。
接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员。
接口是一组行为规范;抽象类是一个不完全的类,着重族的概念。
接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。
接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。
请记住,面向对象思想的一个最重要的原则就是:面向接口编程。
借助接口和抽象类,23个设计模式中的很多思想被巧妙的实现了,我认为其精髓简单说来就是:面向抽象编程。
抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
接口着重于CAN-DO关系类型,而抽象类则偏重于IS-A式的关系;
接口多定义对象的行为;抽象类多定义对象的属性;
接口定义可以使用public、protected、internal 和private修饰符,但是几乎所有的接口都定义为public,原因就不必多说了。
“接口不变”,是应该考虑的重要因素。所以,在由接口增加扩展时,应该增加新的接口,而不能更改现有接口。
尽量将接口设计成功能单一的功能块,以.NET Framework为例,IDisposable、IDisposable、IComparable、IEquatable、IEnumerable等都只包含一个公共方法。
接口名称前面的大写字母“I”是一个约定,正如字段名以下划线开头一样,请坚持这些原则。
在接口中,所有的方法都默认为public。
如果预计会出现版本问题,可以创建“抽象类”。例如,创建了狗(Dog)、鸡(Chicken)和鸭(Duck),那么应该考虑抽象出动物(Animal)来应对以后可能出现风马牛的事情。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽象类来实现。
从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
对抽象类不能使用new关键字,也不能被密封,原因是抽象类不能被实例化。
在抽象方法声明中不能使用 static 或 virtual 修饰符。
反射的定义:一个运行的程序查看自身的元数据或其他程序的元数据的行为称之为反射。
特性的定义:是一种允许我们向程序的程序集增加元数据的语言结构,特性本身也是一种类
特性使用 1、obosolete
2、conditional
注释掉第一行,只会输出“Doing work in Main”
string详解:
注意Intern :总是返回引用和IsIntern方法有可能返回null
字面字符串(verbatim string),为C#提供了声明字符串的特殊方式,用于将引号之间的所有字符视为字符串的一部分,例如: string strPath = @"C:\Program Files \Mynet.exe"; 上述代码,完全等效于:
string strPath = "C:\\Program Files \\Mynet.exe";
System.Enum类型是引用类型,并且是一个抽象类。
l System.Enum类型继承自System.ValueType类型,而ValueType类型是一切值类型的根类,但是显然System.Enum并非值类型,这是ValueType唯一的特例
异常:异常是对程序接口隐含假设的一种违反!