《Effective_C#_中文版_改善C#程序的50种方法教学教材.doc》由会员分享,可在线阅读,更多相关《Effective_C#_中文版_改善C#程序的50种方法教学教材.doc(568页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Good is good, but better carries it.精益求精,善益求善。Effective_C#_中文版_改善C#程序的50种方法-EffectiveC#中文版改善C#程序的50种方法内容提要3编辑推荐3前言4本书面向的读者4本书内容5关于条款5版式和代码约定6关于C#2.06致谢7第一章C#语言元素9原则1:始终能的使用属性(property),而不是可直接访问的DataMember9原则2:为你的常量选择readonly而不是const14原则3:选择is或者as操作符而不是做强制类型转换17原则4:用条件属性而不是#if23原则5:始终提供ToString()26原则
2、6:区别值类型数据和引用类型数据31原则7:选择恒定的原子值类型数据34原则8:确保0对于值类型数据是有效的39原则9:明白几个相等运算之间的关系42原则10:明白GetHashCode()的缺陷46原则11:选择foreach循环50第二章.Net资源管理53原则12:选择变量初始化而不是赋值语句56原则13:用静态构造函数初始化类的静态成员57原则14:使用构造函数链59原则15:使用using和try/finally来做资源清理63原则16:垃圾最小化67原则17:装箱和拆箱的最小化69原则18:实现标准的处理(Dispose)模式73第三章用C#表达你的设计76原则19:选择定义和实现
3、接口,而不是继承77原则20:明辨接口实现和虚函数重载的区别81原则21:用委托来表示回调83原则22:用事件定义对外接口84原则23:避免返回内部类对象的引用89原则24:选择申明式编程而不是命令式编程91原则25:让你的类型支持序列化95原则26:用IComparable和IComparer实现对象的顺序关系100原则27:避免使用ICloneable104原则28:避免转换操作107原则29:仅在对基类进行强制更新时才使用new修饰符109第四章创建基于二进制的组件111原则30:选择与CLS兼容的程序集113原则31:选择小而简单的函数116原则32:选择小而内聚的程序集118原则33
4、:限制类型的访问120原则34:创建大容量的WebAPI122第五章和Framework一起工作125原则35:选择重写函数而不是使用事件句柄125原则36:利用.Net运行时诊断127原则37:使用标准的配置机制130原则38:使用和支持数据绑定132原则39:使用.Net验证136原则40:根据需求选择集合139原则41:选择DataSet而不是自定义的数据结构144原则42:使用特性进行简单的反射151原则43:请勿滥用反射155原则44:创建应用程序特定的异常类158第六章杂项161原则45:选择强异常来保护程序162原则46:最小化与其它非托管代码的交互164原则47:选择安全的代码
5、168原则48:了解更多的工具和资源170原则49:为C#2.0做好准备172原则50:了解ECMA标准177s177内容提要本书围绕一些关于C#和.NET的重要主题,包括C#语言元素、.NET资源管理、使用C#表达设计、创建二进制组件和使用框架等,讲述了最常见的50个问题的解决方案,为程序员提供了改善C#和.NET程序的方法。本书通过将每个条款构建在之前的条款之上,并合理地利用之前的条款,来让读者最大限度地学习书中的内容,为其在不同情况下使用最佳构造提供指导。本书适合各层次的C#程序员阅读,同时可以推荐给高校教师(尤其是软件学院教授C#/.NET课程的老师),作为C#双语教学的参考书。作者简
6、介Billwagner是世界知名的NET专家,微软C#领域的MVP,并荣获微软RegionalDirector称号。他是著名软件咨询公司SRTSolutions的创始人,有20多年软件开发经验,曾经领导了众多成功的Windows平台产品的开发。他是微软开发社区的活跃人物,长期担任MSDNMagazine、ASPNETPro、VisualStudioMagazine等技术杂志的专栏作者。他的blog是编辑推荐业界专家经验荟萃,讲述从优秀到卓越的秘诀,涵盖C#2.0。“一直以来,读者们总在不停地问我,什么时候写EffectiveC#?本书的出版使我如释重负。令人高兴的是,我本人已经从阅读Bill的
7、著作中获益良多,相信读者也会和我一样。”ScottMeyers,EffectiveC+作者,世界级面向对象技术专家C#与C+、Java等语言的相似性大大降低了学习难度。但是,C#所具有的大量独特的特性和实现细节。有时又会使程序员适得其反:他们往往根据既有经验,错误地选用了不恰当的技术。从而导致各种问题。与此同时,随着数年来C#的广泛应用,业界在充分利用C#的强大功能编写快速、高效和可靠的程序方面也积累了丰富的最佳实践。本书秉承了ScottMeyers的EffectiveC+和JoshuaBloch的EffectiveJava所开创的伟大传统用真实的代码示例,通过清晰、贴近实际和简明的阐述,以条
8、款格式为广大程序员提供凝聚了业界经验结晶的专家建议。本书中,著名.NET专家BillWagner就如何高效地使用C#语言和NET库。围绕C#语言元素、NET资源管理、使用C#表达设计、创建二进制组件和使用框架等重要主题,讲述了如何在不同情况下使用最佳的语言构造和惯用法,同时避免常见的性能和可靠性问题。其中许多建议读者都可以举一反三。立即应用到自己的日常编程工作中去。前言本书就如何高效使用C#语言和.NET库,为程序员们提供了一些实用的建议。本书由50个关键条款(也可看作是50个小主题)组成,这些主题反映了我(及其他C#顾问)和C#开发人员共事时遇到的最常见问题。与很多C#开发人员一样,我是在从
9、事10多年C+开发之后开始使用C#的。在本书中,讨论了哪些情况下遵循C+实践可能会在使用C#时引发的问题。有一些使用C#的开发人员有着深厚的Java背景,他们可能会发现有些变化相当明显。因为从Java到C#,一些最佳实践发生了改变,我建议Java开发者要格外注意有关值类型的论述(参见第1章)。此外,.NET垃圾收集器和JVM垃圾收集器的行为方式也不尽相同(参见第2章)。本书中的条款汇集了我最常提供给开发者的建议。虽然并非所有条款都是通用的,但大多数条款都可以很容易地应用到日常的编程工作中。这些条款涵盖了对属性(条款1)、条件编译(条款4)、常量性类型(条款7)、相等判断(条款9)、IClone
10、able(条款27)和new修饰符(条款29)的论述。我的经验是,在大多数情况下,减少开发时间和编写出色的代码应该是程序员的主要目标。某些科学和工程应用程序最重视的可能是系统的整体性能。对其他应用程序而言,凡事都应该围绕可伸缩性展开。对于不同的目标,可能会找到某些情况下比较重要(或不太重要)的信息。针对这一问题,我设法对各种目标进行了详细的解释说明。书中关于readonly和const(条款2)、可序列化的类型(条款25)、CLS兼容(条款30)、Web方法(条款34)和DataSet(条款41)的讨论针对某些特定的设计目标。这些目标在相应的条款中有清楚的说明,这样读者就可以在特定的情况下决定
11、最适用的做法。虽然本书中的每个条款都是独立的,但是这些条款是围绕一些重要的主题(如C#语法、资源管理和对象及组件设计)组织起来的,理解这一点非常重要。这并非无心之举。我的目的就是通过将每个条款构建在之前的条款之上,并合理地利用之前的条款,来让读者最大限度地学习书中的内容。尽管如此,大家仍然不要忘了举一反三。对于特定的问题,本书也可以作为一个理想的查询工具。要记住的是,本书并不是C#语言的教程或指南,也不是为了教授大家C#语法或结构。我的目标是为大家在不同的情况下使用什么语言构造最好提供指导。本书面向的读者本书是为专业的开发人员,也就是那些在日常工作中使用C#的程序员们编写的。本书的阅读前提是读
12、者有面向对象的编程经验,并且至少用过一种C系列语言(C、C+、C#或Java)。有VisualBasic6背景的开发人员在阅读本书之前,应该先熟悉C#语法和面向对象设计。另外,读者应该在.NET的重要领域有一些经验:WebServices、ADO.NET、WebForms和WindowsForms。为了充分利用本书,大家应该理解.NET环境处理程序集的方式、微软中间语言(MSIL)和可执行代码。C#编译器生成的程序集会包含MSIL,我经常将其简写为IL。加载程序集的时候,JIT(JustInTime)编译器会将MSIL转换为机器可执行的代码。C#编译器确实会执行一些优化,但是JIT编译器会负责
13、处理很多更高效的优化,如内联。在书中,我对各种优化所涉及的过程进行了说明。这种两阶段的编译过程对于在不同情形下哪种构造的表现最佳有着很重要的影响。本书内容第1章“C#语言元素”讨论的是C#语法元素和System.Object的核心方法,System.Object是编写每一个类型都要涉及的。声明、语句、算法和System.Object接口,这些都是编写C#代码时必须时刻记住的主题。此外,与值类型和引用类型之间的区别直接相关的条款也都在本章。根据使用的是引用类型(类)还是值类型(结构),很多条款内容都有一些不同。在深入阅读本书之前,我强烈建议大家先阅读有关值类型和引用类型的讨论(条款68)。第2章
14、“.NET资源管理”涵盖了C#和.NET的资源管理问题。大家会学习如何针对.NET管理的执行环境优化资源分配和使用模式。是的,.NET垃圾收集器使我们的工作简单了很多。内存管理是环境的职责,而非开发人员的职责。但是,我们的行为对垃圾收集器在应用程序中的执行效果会产生大的影响。而且,尽管内存不是我们的问题,但管理非内存资源仍然是我们的职责,后者可以通过IDisposable进行处理。在这里,大家可以学习.NET中资源管理的最佳做法。第3章“使用C#表达设计”从C#的角度讲解了面向对象设计。C#提供了丰富的工具供我们使用。有时候,相同的问题可以用很多不同的方法解决:使用接口、委托、事件或者特性和反
15、射。选用哪一种方式,对系统将来的可维护性会产生很大的影响。选择最佳的设计表示可以帮助程序员们更容易地使用类型。最自然的表示会使我们的意图更加清晰。这样,类型就会比较容易使用,而且不容易误用。第3章中的条款集中讲解了我们所做的设计决定,以及各种C#惯用法最适用的场合。第4章“创建二进制组件”讲解了组件和语言互操作性。大家将学习如何在不牺牲C#功能的情况下,编写可被其他.NET语言使用的组件。还将学习如何将类细分成组件,来升级应用程序的某些部分。我们应该能在不重新发布整个应用程序的情况下发布组件的新版本。第5章“使用框架”讲解了.NET框架未充分使用的部分。我看到很多开发人员非常希望创建自己的软件
16、,而不是使用已经构建好的软件。这可能是由.NET框架的体积造成的,也可能因为框架是全新的。这些条款涵盖了框架中那些我曾见过开发人员做重复劳动、而非使用业已存在的功能的部分。通过学习更高效地使用框架,大家可以节省宝贵的时间。第6章“杂项讨论”以不适合其他分类的条款以及对未来的展望作为全书的结尾。有关C#2.0、标准、异常安全(exception-safe)的代码、安全和互操作的信息,都可以在这里找到。关于条款我写这些条款是为了向大家提供编写C#软件的简洁明了的建议。书中有一些指导方针是通用的,因为它们会影响程序的正确性,如正确初始化数据成员(参见第2章)。有一些指导方针不是很容易理解,并且在.N
17、ET社区中引发过很多争论,如是否使用ADO.NETDataSet。我个人认为使用它们可以节省很多时间(参见条款41),其他一些专业的程序员,同时也是我非常尊敬的程序员,对此并不同意。它其实取决于我们正在构建的软件性质。我的立场是尽量节省时间。如果是编写大量在基于.NET和基于Java的系统之间传输信息的软件,DataSet就是个糟糕的主意。在整本书中,我为所做的全部建议都给出了理由。如果其理由并不适用于你碰到的情况,那就不要采纳书中的建议。当建议是普遍适用时,我通常会省略其显而易见的理由:如果不这样做,程序就起不了作用。版式和代码约定写编程语言图书的一个困难之处在于,语言设计者用一些英文单词表
18、示非常特殊的新含义,这就导致了一些很难理解的句子。“Developinterfaceswithinterfaces”就是一个例子。因此,我在使用语言关键字时,都采用了代码体。本书使用了很多相关的C#术语。在提到类型的成员时,它是指可以成为类型的一部分的任何定义:方法、属性、字段、索引器、事件、枚举或者委托。当应用的只是一种定义时,我会使用一个更加具体的术语。对于书中的许多术语,大家可能熟悉,也可能还不熟悉。当这些术语第一次在正文中出现时,它们会以楷体形式表现,并给出定义。本书的范例都是简短、专注的代码段,以示范特定条款中的建议。列出它们是为了强调遵循建议的好处。它们并不是可以加入到读者当前程序
19、中的完整范例。大家不能简单地复制代码清单,然后编译它们。所有代码清单我都省略了很多细节。在所有情况下,我们都预设已存在如下常用的using语句:usingSystem;usingSystem.IO;usingSystem.Collections;usingSystem.Data;当使用不太常见的命名空间时,我会确保让读者看到相关的命名空间。简短的范例会使用完全限定类名称,而长的范例则会包含不太常用的using语句。范例中的代码也比较随意。例如,当显示下列代码时:strings1=GetMessage();如果和论述的内容无关,我可能不会显示GetMessage()例程的主体。当我省略代码时,读
20、者可以假定缺失的方法做的是一些明显且合理的事情。我这样做的目的是为了让我们把焦点聚在特殊的主题上。通过省略和主题无关的代码,我们的注意力就不会分散。这样还能让各个条款保持简短,以使大家能够在短时间内完成学习。关于C#2.0我之所以对新的C#2.0版本所言甚少,有两个原因。首先,本书中的大部分建议也同样适用于C#2.0。虽然C#2.0是一个非常重大的升级版本,但它是建立在C#1.0基础之上的,且并没有让现如今的建议失效。对于最佳实践有可能发生变化的地方,我已经在文中给出了说明。第二个原因是现在编写新的C#2.0功能的高效用法还为时过早。本书的内容是基于我以及我的同事使用C#1.0的已有经验。我们
21、对于C#2.0中的新功能还没有足够的经验,因而也就不了解能够应用到日常任务中的最佳做法。当在书中编写C#2.0新功能的高效用法的时机还未成熟时,我并不想误导读者。建议、反馈及获取本书的更新内容本书内容基于我的经验以及和同事们的交流。如果读者有不同的经验,或者有任何疑问或意见,我愿洗耳恭听。请通过电子邮件和我联系:wwagner。我会把这些意见放在网上,作为本书的延伸。登录致谢虽然写作似乎是一件孤独的事情,但本书却是一大群人的成果。我非常幸运,认识两位出色的编辑StephaneNakib和JoanMurray。StephaneNakib第一次联系我为AddisonWesley写作是在一年多以前。
22、我当时心存疑虑,因为书店里到处都是.NET和C#方面的书籍。在C#2.0面世了足够的时间,可以大书特书之前,我一直看不出为C#和.NET再写一本参考书、教程或编程书籍的必要性。我们讨论过好几个想法,话题总是回到写一本有关C#最佳实践的图书。在进行这些讨论的过程中,Stephane告诉我,ScottMeyers开始着手主编一个Effective系列,其风格延续了他的EffectiveC+系列图书。我买的Scott的三本书都被我翻得非常破旧。我还将它们推荐给了我认识的每一位专业C+程序员。他的写作风格清晰而简明。每一个建议条款都有过硬的理由。Effective丛书是很好的资源,而且其体例使得读者很
23、容易就能记住其中的建议。我认识很多C+开发人员,他们复印了书的目录,并把它钉在书房的墙上,不断提醒自己。Stephane一提到写作EffectiveC#的想法,我就欣然接受了这个机会。这本书把我曾为C#开发人员给出的所有建议收录在一起。我很荣幸能成为该系列图书的一个作者。和Scott一起工作让我学到了很多东西。我真心希望本书能够像Scott的书提高了我的C+技巧那样,帮助大家提高C#应用技巧。Stephane帮助落实了写作EffectiveC#的想法,她审读了提纲和草稿,并在该书的早期写作过程中给予了充分的支持。当她抽身离开的时候,JoanMurray接管了这个项目,并毫无倦怠地负责了原稿的写
24、作管理。EbonyHaight作为编辑助理,在整个过程中提供了不间断的帮助。KristaHansing完成了所有编辑和转换编程行话的工作。ChristyHackerd完成了所有把Word文档转变为成书的工作。书中如有错误,应由我来负责。出色的审稿团队修改了绝大多数的错误、冗长和表述不清的问题。最值得一提的是,BrianNoyes、RobSteel、JoshHolmes和DougHolland使得最终的正文比初期的草稿更加正确和有用。另外,还要感谢安阿伯计算机学会、大湖区.NET用户组、GreaterLansing用户组和西密歇根州.NET用户组的所有成员,他们听取了有关这些条款的议论,并提供了
25、出色的反馈。特别要提到的是,ScottMeyers的参与对本书的最终版本有着巨大的积极影响。和他讨论本书的早期草稿,使得我更加明白为什么自己会把EffectiveC+丛书用得破旧不堪。再小的问题,也逃不过他的眼睛。我要感谢MySTTechnologyPartners(myst-)的AndySeidl和BillFrench。我使用了一个基于MyST的安全博客网址向审稿人公布了各个条款的早期草稿。之后我们向公众公开了部分站点,以便大家能够以在线的格式看到本书的部分内容。登录到目前为止,我已经为杂志写了好几年的文章,我要在此感谢那个将我引进门的人:RichardHaleShaw。他在自己参与创办的杂
26、志VisualC+开发者上邀请我这个未经检验的作者开设了一个专栏。如果没有他的帮助,我不会发现自己对写作的热爱。没有他最初给我的帮助,我也不会有机会为VisualStudio杂志、C#Pro或ASP.NETPro撰稿。一路走来,我幸运地和不同杂志的很多出色的编辑共过事。我想把他们的名字全都列在这里,但空间不允许。有一个人非提不可,那就是EldenNelson。我享受与他共事的所有时光,他对我的写作风格产生了很大的积极影响。我的业务伙伴JoshHolmes和DianneMarsh,他们容忍了我对公司业务的有限参与,而让我把时间用来写作本书。他们还帮助审阅了我的原稿、想法和条款中的思想。在整个漫长
27、的写作过程中,我的父母Bill和AliceWagner“做事要有始有终”的忠告,成为我最终完成本书的唯一原因。最后也是最重要的,我要感谢我的家人Marlene、Lara、Sarah和Scott。写书会占用大量的业余时间。在我为本书付出了所有时间之后,他们表现出来的却是始终如一的耐心。第一章 C#语言元素为什么程序已经可以正常工作了,我们还要改变它们呢?答案就是我们可以让它们变得更好。我们常常会改变所使用的工具或者语言,因为新的工具或者语言更富生产力。如果固守旧有的习惯,我们将得不到期望的结果。对于C#这种和我们已经熟悉的语言(如C+或Java)有诸多共通之处的新语言,情况更是如此。人们很容易回
28、到旧的习惯中去。当然,这些旧的习惯绝大多数都很好,C#语言的设计者们也确实希望我们能够利用这些旧习惯下所获取的知识。但是,为了让C#和公共语言运行库(CommonLanguageRuntime,CLR)能够更好地集成在一起,从而为面向组件的软件开发提供更好的支持,这些设计者们不可避免地需要添加或者改变某些元素。本章将讨论那些在C#中应该改变的旧习惯,以及对应的新的推荐做法。原则1:始终能的使用属性(property),而不是可直接访问的DataMemberAlwaysusepropertiesinsteadofaccessibledatamembers.在C#里,Property已经晋升为一类
29、公民。如果你的类里还有Public的变量,Stop!如果你还在手写getandset方法,Stop!Property在不破坏你类的封装的情况下,仍可以把类的datamember变成publicinterface的一部分。访问Property的方式和访问datamember的方式一样,但Property是用methods实现的。有些类的成员只能用data最好的表示,比如:你一个客户的名字,一个点的坐标,等等。而Property就是用来欺骗使用你类的客户,让它们错误的认为它们在访问你类的public变量。你还可以通过Property的实现方法来控制Property的访问。.NetFramework
30、假定你使用Property来让外界访问你类里想让外界访问到的datamember(也就是publicdatamember)。实际上也是这样的,因为.Net的databinding只支持Property,而不支持publicdatamember的访问。Databinding的目的就是把一个object的Property绑定到一个用户界面的control上,webcontrol或者windowsformcontrol.Databinding是通过reflection来实现的,如下例:textBoxCity.DataBindings.Add(Text,address,City);这段code就是把t
31、extBoxCity的TextProperty绑定到address这个object的CityProperty上。如果你把address的CityProperty改成publicdatamember,这段code是不会运行的。因为.NetFrameworkClassLibrary的设计者不支持你的这种行为,他们认为publicdatamember是非常不好的行为和习惯,所以他们不会支持,他们想让你遵从正确的ObjectOriented设计方法。Databinding也不会去找getandsetmethods,所以一定要用Property,而不是传统的getandsetmethods.你也许要说,
32、databinding只适用于那些含有要显示在用户界面的元素的类。但实际情况并不是这样,对于你所有的类,都要使用Property而不是publicdatamember。因为当有新的需求时,通过修改Property的实现方法来适应这个新的需求,要比在你的程序里修改所有的publicdatamember去适应这个需求容易太多了。比如说你以前定义了一个类customer,现在你发现由于当初的粗心没有强制customer姓名不能为空,如果你使用了Property,你可以非常轻松的添加一个检查机制,如下面这段code:publicclassCustomerprivatestring_name;publi
33、cstringNamegetreturn_name;setif(value=null)|(value.Length=0)thrownewArgumentException(Namecannotbeblank,Name);_name=value;/.如果你使用了publicdatamember,你就要找遍你的程序,在每个地方都修改,那样就很愚蠢了。而且浪费了无数青春好时光。因为Property是用methods实现的,所以添加multi-threaded的支持是非常方便的。比如想要添加同步访问的支持:publicstringNamegetlock(this)return_name;setlock
34、(this)_name=value;因为Property是用methods实现的,所以它拥有methods所拥有的一切。Property可以被定义为virtual:publicclassCustomerprivatestring_name;publicvirtualstringNamegetreturn_name;set_name=value;/.显而易见,你也可以把Property扩展为abstract,甚至成为interface的一部分。publicinterfaceINameValuePairobjectNameget;objectValueget;set;你当然也可以扩展出const和
35、nonconst版本的interface。publicinterfaceIConstNameValuePairobjectNameget;objectValueget;publicinterfaceINameValuePairobjectValueget;set;/usage:publicclassStuff:IConstNameValuePair,INameValuePairprivatestring_name;privateobject_value;#regionIConstNameValuePairMemberspublicobjectNamegetreturn_name;objectI
36、ConstNameValuePair.Valuegetreturn_value;#endregion#regionINameValuePairMemberspublicobjectValuegetreturn_value;set_value=value;#endregion如前所述,Property是访问内部数据的method的扩展,它拥有memberfunction的一切特性。因为实现Property访问的方法getandset是独立的两个method,在C#2.0中,你可以给它们定义不同的访问级别,来更好的控制类成员的可见性,如下例:publicclassCustomerprivatest
37、ring_name;publicvirtualstringNamegetreturn_name;protectedset_name=value;/.Property的语法已经超越了单纯的datafield。如果你的类包含indexeditem,你可以使用indexer(参数化的Property),你可以创建一个可返回一个序列元素的Property,如下例:publicintthisintindexgetreturn_theValuesindex;set_theValuesindex=value;/usage:intval=MyObjecti;indexer和单元素Property有着相同的特性
38、。一维的indexer可以用于databinding,二维和多维的indexer可以用来实现其他的数据结构,比如map和dictionary:publicAddressthisstringnamegetreturn_theValuesname;settheValuesname=value;多维的indexer的每个axis上的数据类型可以相同,也可以不同:publicintthisintx,intygetreturnComputeValue(x,y);publicintthisintx,stringnamegetreturnComputeValue(x,name);所有的indexer都必须也
39、只能用this来定义,所以参数表相同的indexer,每个类最多只能有一个。因为使用Property和datamember对于数据访问的code没有什么区别,比如:publicclassCustomerpublicstringName;/.在这个类中使用了publicdatamember,数据访问的code如下:stringname=CustomerOne.Name;CustomerOne.Name=customername;你也许会想,如果在以后的修改中,用Property来代替publicdatamember是可行的,因为数据访问的code相同,但实际上这是行不通的。确实,访问Proper
40、ty和访问datamember的code是相同的,但Property不是data,访问Property所产生的ILcode和数据访问的ILcode是不一样的。所以访问Property和访问datamember只具有code兼容性,而不具有binary的兼容性。如果有兴趣,你可以使用Reflector(你会发现在使用Property的类中,存在.propertydirective,这个directive定义了Property的类型以及getandset实现方法。Getandset都被标注为hidebysig,specialname。也就是说它们不能被C#源代码直接调用,它们也不是正是的类型定义。
41、你只能通过Property来访问它们。C#的编译器会根据类的情况(是用Property还是datamember)来自动产生不同的ILcode。如上所述,访问Property和访问datamember只具有code兼容性,而不具有binary的兼容性。所以,如果你改变最初的设计,用Property来代替publicdatamember的话,你必须重新编译整个程序。这使得升级已经部署的程序或assembly是非常的麻烦。那么两种实现谁的效率更好呢?Property确实不会比publicdatamember快,但也不一定会慢。因为JIT对Property的存取方法setandget进行inline的
42、优化。这时,Property和publicdatamember的效率是一样的。即使Property的存取方法没有被inline优化,它和publicdatamember的效率差别也只是一个可以忽略的functioncall。只有在很少的情况下,这种差别才可以被测量出来。总而言之,当你想让你类内部的数据被外界访问到时(不管是public还是protected),一定要用Property。对于序列和字典,使用indexer。你类的datamember永远应该是private,绝无例外。使用Property,你可以得到如下好处:1Databinding支持2对于需求变化有更强的适应性,更方便的修改实
43、现方法记住,现在多花1分钟使用Property,会在你修改程序以适应设计变化时,为你节约n小时。原则2:为你的常量选择readonly而不是constPreferreadonlytoconst对于常量,C#里有两个不同的版本:运行时常量和编译时常量。因为他们有不同的表现行为,所以当你使用不当时,将会损伤程序性能或者出现错误。两害相权取其轻,当我们不得不选择一个的时候,我们宁可选择一个运行慢一点但正确的那一个,而不是运行快一点但有错误的那个。基于这个理由,你应该选择运行时常量而不是编译时常量(译注:这里隐藏的说明了编译时常量效率更高,但可能会有错误)。编译时常量更快更直接,但在可维护性上远不及运
44、行时常量。保留编译时常量是为了满足那些对性能要求克刻,且随着程序运行时间的过去,其值永远不发生改变的常量使用的(译注:这说明编译时常量是可以不被C#采用的,但考虑到性能问题,还是做了保留)。你可以用关键字readonly来声明(declare)一个运行时常量,编译时常量是用关键字const声明的。/Compiletimeconstant:publiccocnstint_Millennium=2000;/Runtimeconstant:publicstaticreadonlyint_ThisYear=2004;编译时常量与运行时常量不同之处表现在如何对他们的访问上。一个编译时常量会被目标代码中的
45、值直接取代。下面的代码:if(myDateTime.Year=_Millennium)会与下面写的代码编译成完全相同的IL代码:if(myDateTime.Year=2000)运行时常量的值是在运行时确定的。当你引用一个只读常量时(read-only)IL会为你引用一个运行时常量的变量,而不是直接使用该值。当你任意的使用其中一个常量时,这些区别就在一些限制上表现出来。编译时常量只能是基本类型(primitivetypes)(built-inintegralandfloating-poingtypes),枚举或者是字符串。这些就是你只能给运行时常量在初始化时赋值的类型。这些基本类就是可以被编译器在编译IL代码时直接用真实的值所取代的数据类型。下面的代码块(construct)不能通过编译。你不能用new运算符初始化一个编译时常量,即使这个数据类型是值类型。/Doesnotcomplie,usereadonlyinstead:privateconstDateTime_classCreation=newDateTime(2000,1,1,0,0,0);编译时常量仅限于数字和字符串。只读变量,也就是运行时常量,在构造函数(con