摘要: 本文的英文标题为“Distinguish Between Implementing Interfaces and Overriding Virtual Functions”,但是文章的内容主要涉及的是如何在多层继承中使用接口,因此觉得文章标题和内容有些不符(也许我水平比较低,无法真正理解文章的内容)。众所周知,在一个类中对接口所定义方法的实现,默认是不会加上“v... 阅读全文
posted @ 2010-01-26 15:44 Sue_娜 阅读(171) 评论(0) 推荐(0) 编辑
摘要: 委托属于C#中的新名词,它的应用也非常广泛,例如事件就是委托最简单而又直接的例子。那么首先说说什么是委托,其实委托在用过C或者C++的人看来就是函数指针,不过使用C#的大多数人都没有用过这两门语言,因此对委托的理解不是很深,对于委托可以简单的从字面去理解,即“委托别人去执行某些操作”,也就是说执行一个操作,而这个操作过程自身并不知道,只是委托过来让你去执行而已。参看如下这个... 阅读全文
posted @ 2010-01-26 15:44 Sue_娜 阅读(201) 评论(0) 推荐(0) 编辑
摘要: .Net提供了接口,这个不同于Class或者Struct的类型定义。接口有些情况,看似和抽象类一样,因此有些人认为在.Net可以完全用接口来替换抽象类。其实不然,接口和抽象类各有长处和缺陷,因此往往在应用当中,两者要结合来使用,从而互补长短。接下来先说说抽象类和接口的区别。区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是&... 阅读全文
posted @ 2010-01-26 15:42 Sue_娜 阅读(171) 评论(0) 推荐(0) 编辑
摘要: 第二部的主题在于资源管理,.Net编写的程序以托管程序居多,但是并不意味着可以不注意细节,合理的使用.Net提供的便利,加上好的习惯,有利于程序效率提高。这部分包括7个单元,分别如下:Item 12: Prefer Variable Initializers to Assignment Statements《Effective C#》Item 12:推荐使用成员初始化语句Item 13: Init... 阅读全文
posted @ 2010-01-26 15:40 Sue_娜 阅读(125) 评论(0) 推荐(0) 编辑
摘要: 对于托管程序来说,非托管资源来说,需要手动来释放,否则会造成资源泄漏,如果放到析构函数去完成,但是GC调用对象的析构函数时机并不确定,对于资源释放并不及时。换句话说析构函数只是保障资源不被泄漏的方法,但不是最好的方法。比较好的方法,就是使用.Net的IDisposable接口提供的Dispose方法来进行释放。对于程序资源释放,可以参看这篇文章。http://blog.csdn.net/knigh... 阅读全文
posted @ 2010-01-26 15:39 Sue_娜 阅读(233) 评论(0) 推荐(0) 编辑
摘要: 为了便于文章的开展,首先介绍装箱(Boxing)和拆箱(Unboxing)这两个名词。.Net的类型分为两种,一种是值类型,另一种是引用类型。这两个类型的本质区别,值类型数据是分配在栈中,而引用类型数据分配在堆上。那么如果要把一个值类型数据放到堆上,就需要装箱操作;反之,把一个放在堆上的值类型数据取出来,则需要进行拆箱操作。例如,对于如下简单的装箱和拆箱操作语句。 int i = 123; obj... 阅读全文
posted @ 2010-01-26 15:35 Sue_娜 阅读(150) 评论(0) 推荐(0) 编辑
摘要: 对于.Net所写一般程序来说,都属于托管程序,内存的释放和回收是由Garbage Collector完成。但是相对于栈上内存操作而言,GC回收堆上的内存,会消耗更多的CPU时间,这方面的内容可以参看这篇文章。http://blog.csdn.net/knight94/archive/2006/08/05/1023352.aspx因此如果让GC不停的释放和回收内存,会造成程序性能的下降。例如对于如下... 阅读全文
posted @ 2010-01-26 15:25 Sue_娜 阅读(202) 评论(0) 推荐(0) 编辑
摘要: 我以前写过一篇文章,关于.Net资源释放问题,也就是对于非内存的资源,最好使用IDisposable接口提供的Dispose来释放,详情参看这篇文章。http://blog.csdn.net/knight94/archive/2006/08/05/1023352.aspx很明显,Dispose方法是一个外部方法,系统并不会帮你调用。为了尽早释放对象所占用的资源,所以需要保证Dispose方法能尽早... 阅读全文
posted @ 2010-01-26 12:01 Sue_娜 阅读(166) 评论(0) 推荐(0) 编辑
摘要: 在写程序的时候,往往会出现为一个类型提供不同场景的构造函数,可能大多构造函数比较相似,而C#中又不允许缺省参数,因此构造函数的编写无疑是一个重复工作。但是使用Copy和Paste来完成构造函数的编写,有时候很难达到统一,尤其是当成员发生变化的时候。因此比较常见的替换方法就是为构造函数提供一个统一的成员函数来完成初始化工作。例如: public class MyClass { private int... 阅读全文
posted @ 2010-01-26 12:00 Sue_娜 阅读(233) 评论(0) 推荐(0) 编辑
摘要: 编写程序的时候难免要使用到静态成员,由于静态成员的访问是脱离类型对象的,所以使用非静态构造函数,私有方法或者一些其他方法都是不合理的。.Net提供了成员初始化语句和静态构造函数来初始化静态成员。根据上一个单元,我们可以知道静态成员的初始化语句会早于静态构造函数执行,其次还知道成员初始化语句的好处和一些限制。这里要提的一点就是,静态构造函数和实例构造函数之间的区别,因为静态构造函数是由CLR调用执行... 阅读全文
posted @ 2010-01-26 11:58 Sue_娜 阅读(241) 评论(0) 推荐(0) 编辑
摘要: 为了方便内容的开展,先说说一个对象的构造过程。对于类型第一个实例的构造过程大致如下:1. 分配静态成员的内存空间,此时空间存储数据为0;2. 执行静态成员的初始化语句;3. 执行基类的静态构造函数;4. 执行类型的静态构造函数;5. 分配成员的内存空间,此时空间存储数据为0;6. 执行成员的初始化语句;7. 执行相应的基类构造函数;8. 执行类型的构造函数。那么对于同类型的后续创建对象,前4个步骤... 阅读全文
posted @ 2010-01-26 11:56 Sue_娜 阅读(234) 评论(0) 推荐(0) 编辑
摘要: 第一部分是语言使用的基础,而这是使用语言的基本功,也是平常最不注意的,养成好的习惯,有利于后期水平提高。这部分包括前面11个单元,分别如下:Item 1: Always Use Properties Instead of Accessible Data Members《Effective C#》Item 1:用属性来访问类的私有成员Item 2: Prefer readonly to const《... 阅读全文
posted @ 2010-01-26 11:51 Sue_娜 阅读(151) 评论(0) 推荐(0) 编辑
摘要: 循环语句是编程的基本语句,在C#中除了沿用C语言的循环语句外,还提供了foreach语句来实现循环。那么我要说的就是,在循环操作中尽量使用foreach语句来实现。为了来更好地说明为什么要提倡使用foreach,用如下三种不同方式来编写循环语句。 int[] nArray = new int[100]; // Use "foreach" to loop array foreach( int i i... 阅读全文
posted @ 2010-01-26 11:49 Sue_娜 阅读(175) 评论(0) 推荐(0) 编辑
摘要: GetHashCode函数,看了它的名字就知道它会被用在哪里。没错,这个函数一般是在操作HashTable或者Dictionary之类的数据集的时候被调用。每个类型,不管是值类型还是引用类型,都提供这个基本函数,同样也可以像重写ToString或者Equals函数一样去重写它。但是我这里要说的,不建议重写此函数,而且在使用这个函数也需要加倍小心。Why? 有些人看了我所说的,会产生类似的疑问。我这... 阅读全文
posted @ 2010-01-26 11:46 Sue_娜 阅读(181) 评论(0) 推荐(0) 编辑
摘要: .Net有四个判等函数?不少人看到这个标题,会对此感到怀疑。事实上确是如此,.Net提供了ReferenceEquals、静态Equals,具体类型的Equals以及==操作符这四个判等函数。但是这四个函数之间有细微的关系,改变其中一个函数的实现会影响到其他函数的操作结果。首先要说的是Object.ReferenceEquals和Object.Equals这两个静态函数,对于它们俩来说,是不需要进... 阅读全文
posted @ 2010-01-26 11:43 Sue_娜 阅读(151) 评论(0) 推荐(0) 编辑
摘要: 大家在看了这标题后,肯定会觉的,为什么要确保“0”是有效的,这一点主要是跟值类型的内存分配有关,值类型有默认的构造函数,这是没法避免的,因此值类型变量中的成员在初始化的时候所出现的细微问题(对于值类型这方面的知识可以参看我前面一篇文章)。http://blog.csdn.net/Knight94/archive/2006/07/01/861383.aspx日常中比较常见的两... 阅读全文
posted @ 2010-01-26 11:32 Sue_娜 阅读(200) 评论(0) 推荐(0) 编辑
摘要: 首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,第二部分为原子,最后一个部分为值类型。最后一部分,我不多说了,限制此章适用的范围。对于什么是不可改变类型,这里的意思是指此类型的变量一旦产生其成员就不能发生变化。至于原子类型,我以前在CSDN也经常提到,例如保证操作的原子性之类的语句,那么一个原... 阅读全文
posted @ 2010-01-26 11:27 Sue_娜 阅读(201) 评论(0) 推荐(0) 编辑
摘要: 在C#中有两种类型的数据,一种是值类型数据,一种是引用类型数据。在编码的时候区分这两种类型数据,可以避免一些细小的编码错误。首先说说什么类型是值类型,例如:int、float、bool之类的基础类型,以及用struct定义的类型,如:DateTime。除此外,如string,数组,以及用class定义的类型等都是引用类型。对于C#来说,很难罗列出所有类型进行一一分别,这需要自己在编码过程中进行分析... 阅读全文
posted @ 2010-01-26 11:22 Sue_娜 阅读(161) 评论(0) 推荐(0) 编辑
摘要: 在编写自定义类型的时候,即使我们不写ToString函数,系统也会自动提供ToString函数,例如: public class clsUserInfo { private string strUserName; …… }不过系统所提供ToString函数,并不做太多的事情,无法真实的反映当前对象的一些属性,就如上这段代码,调用ToString返回的结果和GetType... 阅读全文
posted @ 2010-01-26 11:11 Sue_娜 阅读(175) 评论(0) 推荐(0) 编辑
摘要: 在编码的时候,有时候需要添加一些DEBUG信息,来为了方便调试程序,但是到了真正发布的时候,又不希望把这些信息进行编译发布。那么在以前C或者C++编码的时候,用IF/ENDIF来定义程序块实现这个功能,而此方法在C#中可以继续沿用。这种用IF/ENDIF来增加DEBUG信息块有两种方式,如下:方式一,在一个函数中进行嵌入,例如:#if DEBUG Trace.WriteLine( "ErrorMe... 阅读全文
posted @ 2010-01-26 11:10 Sue_娜 阅读(239) 评论(0) 推荐(0) 编辑