说明详细的net代码规范_第1页
说明详细的net代码规范_第2页
说明详细的net代码规范_第3页
说明详细的net代码规范_第4页
说明详细的net代码规范_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、.NET设计规范 武汉无线飞翔科技有限公司.NET设计规范1 命名规范1.1 大小写约定PascalCasing将标识符的首字母和后面连接的每个单词的首字母都大写。可以对三字符或更多字符的标识符使用 Pascal 大小写。例如:BackColor camelCasing标识符的首字母小写,而每个后面连接的单词的首字母都大写。例如:backColor对于由多个单词组成的所有公共成员、类ss型及命名空间名称,要使用 Pascal 大小写。对参数名称使用大小写混合。下表汇总了标识符的大小写规则,并提供了不同类型标识符的示例。表 不同类型的标识符的大小写规则标识符 大小写方式 示例 类PascalAp

2、pDomain 枚举类型PascalErrorLevel 枚举值PascalFatalError 事件PascalValueChanged 异常类PascalWebException 只读的静态字段PascalRedValue 接口PascalIDisposable 方法PascalToString 命名空间PascalSystem.Drawing 参数CameltypeName 属性PascalBackColor 首字母缩写词与单词缩写首字母缩写词是由一个短语的首字母组成的,而单词缩写则仅仅把一个单词的长度变短。要把两个字母的首字母缩写词全部大写,除非他是camelCasing风格的参数名的

3、第一个单词。System.IOpublic void StartIO(Stream ioStream)要把由三个或三个以上字母组成的首字母缩写词的第一个字母大写。只有第一个字母大写,除非首字母缩写词是camelCasing风格的标识符的第一个单词。System.Xmlpublic void ProcessHtmlTag(string htmlTag)在涉及大小写时,大多数复合词术语要作为单个单词处理。不要把所谓闭合形式的复合词中每个单词的首字母大写。下表列出一些常用的复合词和常用术语的大小写。表 常用的复合词和常用术语的大小写及拼写Pascal CamelNotBitFlagbitFlagBi

4、tflagCallbackcallbackCallBackCanceledcanceledCancelledDoNotdoNotDontEmaildmailEMailEndpointdndpointEndPointFileNamefileNameFilenameGridlinegridlineGridLineHashtablehashtableHashTableIdidIDIndexesindexesIndicesLogOfflogOffLogOutLogOnlogOnLogInMetadatametadataMetaData, metaDataMultipanelmultipanelMult

5、iPanelMultiviewmultiviewMultiViewNamespacenamespaceNameSpaceOkokOKPipiPIPlaceholderplaceholderPlaceHolderSignInsignInSignOnSignOutsignOutSignOffSqlsqlSQLUserNameuserNameUsernameWhiteSpacewhiteSpaceWhitespaceWritablewritableWriteable1.2 通用命名约定通用命名约定讨论的是如何为库元素选择最适当的名称。这些准则适用于所有标识符。后面各节讨论特定元素(如命名空间或属性)

6、的命名。选择名称1.选择易读的标识符名称。例如,英文属性名称 HorizontalAlignment 比 AlignmentHorizontal 更具可读性。可读性比简洁性更重要。属性名称 CanScrollHorizontally 比 ScrollableX(指 X 轴,但意义不明确)更好。2.不要使用下划线、连字符或任何其他非字母数字字符。3.不要使用匈牙利表示法。匈牙利表示法是在标识符中使用一个前缀对参数的某些元数据进行编码,如标识符的数据类型。 4.避免使用与常用编程语言的关键字冲突的标识符。虽然符合 CLS 的语言必须提供将关键字用作普通字的方法,最佳做法不要求强制开发人员了解如何实

7、现。对于大多数编程语言,语言参考文档都会提供语言所使用的关键字列表。缩写和首字母缩写词通常,不应使用缩写或首字母缩写词。这类名称的可读性较差。同样,要确定某个首字母缩写词是否已受到广泛认可也是很困难的。不要将缩写或缩略形式用作标识符名称的组成部分。例如,使用 OnButtonClick 而不要使用 OnBtnClick。除非必要,不要使用任何未被广泛接受的首字母缩写词。语言特定的名称对于类型名称,应使用语义上有意义的名称而不要使用语言特定的关键字。例如,名称 GetLength 比 GetInt 更好。在标识符的语义含义仅限于其类型的极少数情况下,应使用一般公共语言运行库 (CLR) 类型名称

8、,而不要使用语言特定的名称。例如,将数据转换为 Int16 的方法应命名为 ToInt16 而不是 ToShort,因为 Short 是 Int16 的语言特定的类型名称。 在标识符没有语义含义且参数的类型不重要的极少数情况下,应使用通用名称(如值或项),而不要重复类型名称。1.3 程序集和DLL的命名大多数情况下,程序集包含全部或部分可重用库,且它包含在单个动态链接库 (DLL) 中。一个程序集可拆分到多个 DLL 中,但这非常少见,在此准则中也没有说明。程序集和 DLL 是库的物理组织,而命名空间是逻辑组织,其构成应与程序集的组织无关。命名空间可以且经常跨越多个程序集。一定要为程序集 DL

9、L 选择指示大的功能块(如 System.Data)的名称。程序集和 DLL 的名称不必对应于命名空间名称,但是在命名程序集时遵循命名空间名称这种做法是合理的。考虑按下面的模式命名 DLL:<Company>.<Component>.dll 其中 <Component> 包含一个或多个以圆点分隔的子句。例如,Contoso.WebControls.dll。1.4 名称空间的命名为命名空间选择的名称应指示命名空间中的类型所提供的功能。例如,System.Net.Sockets 命名空间包含的类型允许开发人员使用套接字通过网络进行通信。 命名空间名称的一般格式如

10、下:<Company>.(<Product>|<Technology>).<Feature>.<Subnamespace> 例如,Microsoft.WindowsMobile.DirectX。使用公司名称作为命名空间的前缀以防止不同公司开发的命名空间具有相同的名称和前缀。在命名空间名称的第二级使用稳定的、与版本无关的产品名称。不要根据组织层次结构确定命名空间层次结构中的名称,因为公司的部门名称经过一段时间后可能会改变。命名空间名称是长期使用的、不会更改的标识符。组织的不断发展和变化不应使命名空间名称过时。使用 Pascal 大小写格

11、式,并用句点分隔命名空间各部分(如 Microsoft.Office.PowerPoint)。如果您的品牌采用了非传统的大小写,应遵循您的品牌所定义的大小写,即使它与常用的命名空间大小写相背离也如是。适当的时候可考虑使用复数命名空间名称。例如,使用 System.Collections 而不使用 System.Collection。但是,品牌名称和首字母缩写词属于此规则的例外情况。例如,使用 System.IO,而不要使用 System.IOs。命名空间和其中的类型不要使用相同的名称。例如,不要在将“Debug”用作命名空间名称的同时,又在该命名空间中提供一个名为“Debug”的类。有些编译器

12、要求对这种类型进行完全限定。命名空间和类型的名称冲突如果选择的命名空间或类型的名称与现有名称冲突,则库的用户将不得不对受影响的项的引用进行限定。在大多数开发情况中,都不应出现这种问题。本节提供的某些准则适用于下面的命名空间类别: 应用程序模型命名空间基础结构命名空间核心命名空间技术命名空间组应用程序模型中的命名空间提供特定于应用程序中的某个类的功能集。例如,System.Windows.Forms 命名空间中的类型提供编写 Windows 窗体客户端应用程序所需的功能。System.Web 命名空间中的类型支持编写基于 Web 的服务器应用程序。通常,在同一应用程序中不会使用不同应用程序模型中

13、的命名空间,因此,这降低了名称冲突影响使用您的库的开发人员的可能性。基础结构应用程序提供专门的支持,很少在程序代码中进行引用。例如,程序开发工具所使用的 *.Designer 命名空间中的类型。*.Permissions 命名空间是基础结构命名空间的另一个示例。与基础结构命名空间中的类型的名称冲突不可能影响使用您的库的开发人员。核心命名空间是 System.* 命名空间(不包括应用程序命名空间和基础结构命名空间)。System 和 System.Text 都是核心命名空间的示例。应尽可能避免与核心命名空间中的类型发生名称冲突。属于特定技术的命名空间将具有相同的第一和第二级标识符 (Compan

14、y.technology.*)。应避免在技术命名空间中出现名称冲突。 命名空间一般准则不要引入宽泛的类型名称,如 Element、Node、Log 和 Message。在通常情况下,这样极可能导致类型名称冲突。应对宽泛的类型名称进行限定(例如 FormElement、XmlNode EventLog、SoapMessage)。应用程序命名空间准则不要在单个应用程序模型内为命名空间中的多个类型指定相同的名称。例如,如果要编写 Windows 窗体应用程序开发人员要使用的特殊控件库,则不应引入名为 Checkbox 的类型,因为该应用程序模型已存在同名类型 (CheckBox)。核心命名空间准则不

15、要指定会与核心命名空间中的任何类型发生冲突的类型名称。例如,不要使用 Directory 作为类型名称,因为这会与 Directory 类型冲突。技术命名空间准则不要分配会与单个技术命名空间内的其他类型发生冲突的类型名称。不要引入会导致技术命名空间的类型与应用程序模型命名空间中的类型发生冲突的类型名称1.5 类、结构和接口的命名通常,类型名称应该是名词短语,其中名词是由类型表示的实体。例如,Button、Stack 和 File 都具有名称,用于标识由类型表示的实体。从开发人员的角度选择标识实体的名称;名称应反映使用场合。下面的准则适用于如何选择类型名称。 1. 按照 Pascal 大小写格式

16、,使用名词或名词短语(或偶尔使用形容词短语)为类、接口和值类型命名。2. 不要为类名加前缀(如字母 C)。接口不适用此规则,它应以字母 I 开头。3. 考虑在派生类的末尾使用基类名称。例如,从 Stream 继承的 Framework 类型以 Stream 结尾,从 Exception 继承的类型以 Exception 结尾。4. 为接口名称加上字母 I 前缀,以指示该类型为接口。5. 在定义类/接口对(其中类是接口的标准实现)时,一定要确保类和接口的名称除接口名称以字母 I 为前缀外,二者应完全相同。例如,Framework 提供 IAsyncResult 接口和 AsyncResult 类

17、。1.5.1 泛型类型参数命名要用描述性的名字来命名泛型类型参数,除非一个字母就足够了,而且描述性的名字并不能增加什么价值。public interface IsessionChannel<TSession>.public delegate Toutput Converter<Tinput, TOutput>(Tinput from)public class List<T>.考虑用T来命名参数类型,如果类型只有一个类型参数,且类型参数只有一个字母。public int Icomparare<T> .public delegate bool Pre

18、dicate<T>(T item);public struct Nullable<T> where T:struct .要给描述性的类型参数名加上T前缀public interface IsessionChannel<TSession> where Tsession ;考虑在类型参数名中显示出施加于该类型参数上的限制。例如,可以把一个被限定为ISession的类型参数命名为Tsession。1.5.2 常用类型命名表 派生自或实现某些特点的核心类型的命名规则基类派生类型/实现类型的规范System.Attribute要给自定义的Atrribute类添加“At

19、tribute”后缀。System.Delegate要给用于事件处理的委托添加“EventHandler”后缀。要给用于事件处理之外的那些委托添加“Callback”后缀。不要给委托添加“Delegate”后缀。System.EventArgs要添加“EventArgs”后缀。System.Enum不要派生自该类;要用编程语言的提供的关键字来代替。例如在C#中,要用enum关键字。不要添加“Enum”或“Flag”后缀。System.Exception要添加“Exception”后缀。System.Collections.IDictionary要添加“Dictionary”后缀。System.

20、Collections.Generic. IDictionary<TKey, TValue>System.Collections.IEnumerable要添加“Collection”后缀。System.Collections.ICollectionSystem.Collections.IListSystem.Collections. Generic.ICollection<T>System.Collections. Generic.IList<T>System.IO.Stream要添加“Stream”后缀。System.Security.CodeAccess

21、Permission要添加“Permission”后缀。System.Security.IPermission1.5.3 枚举的名称不要在枚举值名称中使用前缀。例如,不要对 ADO 枚举使用 ad 之类的前缀,也不要对多格式文本枚举使用 rtf 之类的前缀,依此类推。这还意味着不应在枚举值名称中包含枚举类型名称。下面的代码示例演示了不正确的枚举值命名。public enum Teams TeamsAlpha, TeamsBeta, TeamsDelta 不要将 Enum 用作枚举类型的后缀。不要在标志枚举的名称中添加 Flags 作为后缀。对枚举使用单数名称,除非枚举值是位域。对使用位域值的枚

22、举(也称为标志枚举)使用复数名称。1.6 类型成员的命名1.6.1 方法的命名要用动词或动词词组来命名方法。public class Stringpublic int CompareTo(.);public string Split(.);public string Trim();1.6.2 属性的命名要用名词、名词词组或形容词来命名属性。public class String public int Length get;不要让属性名看起来与“GET”方法的名字相似,如下面的例子所示。public string TextWriter get . set . public string GetT

23、extWriter(int value) . 要用肯定性的短语(CanSeek而不是CantSeek)来命名布尔属性。如果有帮助,还可以有选择性地给布尔属性添加“Is”、“Can”或“Has”等前缀。例如,CanRead要比Readable更容易理解,但Created却比IsCreated的可读性更好。前缀通常是多余的,也没有必要,尤其是在有Intellisense的代码编辑器中。输入MyObject.Enabled = 与输入 MyObject.IsEnabled = 一样清楚,两种情况下Intellisense都会提示你选择true或false,但后者更为冗长一些。考虑用属性的类型名来命名

24、属性。例如,下面这个属性的作用是取得和设置一个名为Color的枚举值,因些它被命名为Colors:public enum Color .public class Control public Color Color get . set .1.6.3 事件的命名要用动词或动词短语来命名事件。这样的例子包括Clicked、Painting、DroppedDown等等。要用现在时和过去时来赋予事件名以之前和之后的概念。例如,在窗口关闭之前发生的close事件应该命名为Closing,而在窗口关闭之后发生的应该命名为Closed。不要用“Before”和“After”前缀或后缀来区分前置事件和后置事件

25、。要在命名事件处理函数(用作事件类型的委托)时加上“EventHandler”后缀,如下面的例子所示: public delegate void ClickedEventHandler(object sender,clickedEventArgs e);要在事件处理函数中用sender和e作为两个参数的名字。参数sender表示触发该事件的对象。虽然参数sender可以是一个更为具体的类型,但一般来说其类型就是object。整个.NET框架一致地使用了这种模式。public delegate void<EventName>EventHandler(object sender,<

26、;EventName>EventArgs e);要在命名事件的参数类时加上“EventArgs”后缀,如下面的例子所示:public class ClickedEventArgs : EventArgs int x; int y; public ClickedEventArgs(int x, int y) this.x = x; this.y = y; public int x get return x; public int y get return y; 1.6.4 字段的命名要在命名字段时使用PascalCasing大小写风格。public class String public

27、static readonly string Empty;要用名词或名词短语来命名字段。不要给字段名添加前缀。例如,不要用“g_”或“s_”来区分静态和非静态字段。 1.7 参数的命名要在命名参数时使用camelCasing 大小写风格。public class String public bool Contains(string value); public string Remove(int startIndex,int count);要使用具有描述性的参数名。参数名应该具备足够的描述性,使用在大多数情况下,用户根据参数的名字和类型就能够确定它的意思。考虑根据参数的意思而不是参数的类型来命

28、名参数。开发工具必须向用户提供关于类型的有用信息,这样用户就能更好地利用参数名来描述语义,而不是描述类型。偶尔使用基于类型的参数名是完全可以的,但在采用这些规范时再回到匈牙利命名法则是绝对不应该的。1.8 资源的命名要在命名资源关键字(resource key)时使用PascalCasing大小写风格。要使标识符的名字具有描述性而不是使名字变短。应该尽可能地使名字简短,但前提是不能牺牲可读性。不要使用各主要CLR编程语言特有的关键字。要在命名资源时仅使用字母、数字和下划线。要用点号来给标识符清楚地划分层次。例如,如果要设计菜单系统的资源,那么可以考虑按下面的方式来命名它们:Menus.File

29、Menu.Close.TextMenus.FileMenu.Close.ColorMenus.FileMenu.SaveAs.TextMenus.FileMenu.About.Text要在为异常的消息资源命名时遵循下面的命名约定。资源标识符应该是异常的类型名加上一个简短的异常标识符,之间以点号分隔:ArgumentException.IllegalCharactersArgumentException.InvalidNameArgumentException.FileNameIsMalformed2 类型设计规范要确保每个类型由一组定义明确、相互关联的成员组成,而不仅仅是一些无关功能的随机集合

30、。能用简单的一句话来描述一个类型是非常重要的。一个好的定义应该还能去除那些不怎么有关的功能。2.1 类型和名称空间要用名称空间把类型组织成一个相关的特性域的层次结构。该层次结构应该为开发人员更容易地浏览框架并找到想要的API而优化。避免非常深的名称空间层次。这样的层次难于浏览,因为用户不得不经常地回溯。避免有太多的名称空间。在最常见的场景中,框架的用户应该不需要导入许多的名称空间。只要有可能,就应该把常见场景中一起使用的类型放在一个单独的名称空间中。避免把为高级场景而设计的类型和为常见编程任务而设计的类型放在同一个名称空间中。这使得用户不仅能更容易地理解框架的基本概念,而且能更容易地在常见的场

31、景中使用框架。不要不指定名称空间就定义类型。这把相关的类型组织到一个层次结构中,而且有助于解决可能存在的名字冲突。请注意名称空间有助于解决名字冲突的事实并不意味着应该引入这样的冲突。标准子名称空间的命名1、.Design子名称空间仅用于设计时的类型应该放在名为.Design的子名称空间中。例如,System.Windows.Forms.Design包含了Designers以及相关的类,用来进行基于System.Windows.Forms的应用程序的设计。System.Windows.Forms.DesignSystem.Messaging.DesignSystem.Diagnostics.De

32、sign要用带“.Design”后缀的名称空间来容纳那些为基本名称空间提供设计时的功能的类型。2、.Permissions子名称空间许可类型应该放在名为.Permissions的子名称空间中。要用带“.Permissions”后缀的名称空间来容纳那些为基本名称空间提供自定义许可的类型。3、.Interop子名称空间要用带“.Interop”后缀的名称空间来容纳那些为基本名称空间提供互操作功能的类型。要用带“.Interop”后缀的名称空间来容纳所有位于Primary Interop Assembly(PIA)中的代码。2.2 类和结构之间的选择考虑定义结构而不要定义类-如果该类型的实例比较小而

33、且生命期比较短,或者经常被内嵌在其他对象中。不要定义结构,除非该类型具有以下所有特征:它在逻辑上代表一个独立的值,与基本类型(int、double等等)相似。它的实例的大小小于16个字节。它是不可变的。它不需要经常被装箱。2.3 类和接口之间的选择要优先采用类而不是接口。与基于接口的API相比,基于类的API容易演化得多,因为可以给类添加成员而不会破坏已有的代码。要用抽象类而不是用接口来解除协定与实现之间的耦合。抽象类经过正确的设计,同样能够解除协定与实现之间的耦合,与接口所能达到的程序不相上下。要定义接口,如果需要提供一个多态的值类型层次结构的话。值类型不能自其他类型继承,但它们可以实现接口

34、。例如,Icomparable 、Iformattable以及Iconvertible都是接口,因此Int32、Int64等值类型及其基本类型,都可以是comparable、formattable及convertible的。public struct Int32 : Icomparable,Iformattable,Iconvertible public struct Int64 : Icomparable,Iformattable,Iconvertible 考虑通过定义接口来达到与多重继承相类似的效果。 例如,System.Idisposable和System.Icloneable都是接口,

35、因此诸如System.Drawing.Image之类的类型既可以是disposable、cloneable,而且还可以继承自System.MarshalByRefObject类。public class Image : MarshalByRefObject,Idisposable,Icloneable 2.4 抽象类的设计不要在抽象类型中定义公有的或内部受保护的(protected-internal)构造函数。只有当用户需要创建一个类型的实例时,该类型的构造函数才应该是公有的。由于你无法创建一个抽象类型的实例,因些如果抽象类型具有公有构造函数,那么这样的设计不仅是不当的,而且还会误导用户。/b

36、ad designpublic abstract class Claim public Claim(int number) /good designpublic abstract class Claim /incorrect Designprotected Claim(int number) 要为抽象类定义受保护的构造函数或内部构造函数。受保护的构造函数更为常见,它仅仅是允许当子类型被创建时,基类能够做自己的初始化。public abstract class Claim protected Claim() 要为你发布的抽象类提供至少一个继续自该类的具体要求类型。这有助于验证该抽象类的设计是否正

37、确。例如,System.IO,FileStream是System.IO.Stream抽象类的一个实现。2.5 静态类的设计要尽量少用静态类。静态类应该仅被用作辅助类,来支持框架的面向对象的核心。不要把静态类当做是杂物箱。每一个静态类都应该有其明确的目的。不要在静态类中声明或覆盖实例成员。要把静态类定义为密封的、抽象的,并添加一个私有的实例构造函数-如果你的编程语言没有内置对静态类的支持。2.6 接口的设计要定义接口,如果你需要包括值类型在内的一组类型支持一些公共的API。考虑定义接口,如果你需要让已经自其他类型继承的类型支持该接口提供的功能。避免使用记号接口(没有成员的接口)如果你需要一个具备

38、某特征(记号)的类做记号,一般来说,最好使用自定义attribute而不要使用接口。/Avoidpublic interface Iimmutable /empty interfacepublic class Key : Iimmutable /DoIimmutablepublic class Key 这样就可以实现一些方法,对那些未用指定attribute做标记的参数,这些方法就可以拒绝使用,如下面的样例代码所示:public void Add(Key key,object value) if (!key.GetType().IsDefined(typeof(ImmutableAttribu

39、te),false) throw new ArgumentException(“The parameter must be immutable”,”key”); 要为接口提供至少一个实现该接口的类型。这有助于有助于验证接口的设计。例如,System.Collections.ArrayList是System.Collections.Ilist接口的一个实现。要为你定义的每个接口提供至少一个使用该接口的API(一个以该接口为参数的方法,或是一个类型为该接口的屋性)。这有助于有助于验证接口的设计。例如,List<T>.Sort使用了IComparer<T>接口。不要给已经发行

40、的接口再添加成员。这样做会破坏该接口的实现。为了避免版本的问题,你应该创建一个新的接口。2.7 结构的设计不要为结构提供默认的构造函数。这样就允许在创建结构的数组的同时有必运行数组中每项的构造函数。值和注意的是C#不允许结构有默认的构造函数。要确保当所有有实例数据都为零、false或null(如果合适)时,结构仍处于有效状态。这可以防止在创建一个结构的数组时创建出无效的实例。例如,下面的结构设计得不正确。带参数的构造函数有意用来确保状态有效,但是在创建该结构的数组时,这个构造函数没有被执行,因此所有的实例字段都被初始化为0,而对该类型来说这并不是一个有效的状态。/bad designpubli

41、c struct PositiveInteger int value;public PositiveInteger(int value) if(value <= 0) throw new ArgumentException(); this.value = value;public override string ToString() return value.ToString();通过确保默认的状态(本例中的value字段为0)是该类型的有效逻辑状态,这个问题可以得到解决。/good designpublic struct PositiveInteger int value; /the

42、logical value is value+1public PositiveInteger(int value) if(value <=0) throw new ArgumentException(.); this.value = value-1;public override string ToString() return (value+1) .ToString();要为值类型实现IEquatable<T>。值类型的Object.Equals方法会导致装箱,而且它的默认实现也并不非常高效,因为它使用了反射。Iequatable<T>.Equals的性能要好得

43、多,而且能够实现为不会导致装箱。不是显式地扩展System.ValueType,事实上大多数编程语言不允许这样做。一般来说,结构可以是非常有用的,但它们应该只被用于小型的、单个的、不可变的,而且不会被频繁地装箱的值。2.8 枚举的设计要用枚举来加强那些表示值的集合的参数、属性以及返回值的类型性。要优先使用枚举而不使用静态常量。/Avoid the followingpublic static class Color public static int Red = 0;public static int Green = 1;public static int Blue = 2;/Favor th

44、e followingpublic enum Color Red, Green, 不要把枚举用于开放的集合(比如操作系统的版本、朋友的名字等)。不要提供为了今后使用而保留的枚举值。即使是在后期,你也始终能够给已有的枚举添加值。保留值只会污染实际值的集合,还往往会把用户引向错误。public enum DeskType Circular, Oblong, Rectangular, / the following two values should not be here ReservedForFutureUse1, ReservedForFutureUse2, 避免显式地显露只有一个值的枚举。确

45、保C语言API今后的可扩展性的一个常见的做法就是给方法的签名添加一个保留参数。此类保留参数可以用一个只有一个默认值的枚举来表示。在托管API是不应该这样做。方法重载允许在今后的版本中再添加参数。 / Bad Design public enum SomeOption DefaultOption /we will add more options in the future . / The option parameter is not needed. / It can always be added in the future / to an overload of SomeMethod().

46、 public void SomeMethod(SomeOption option) . 不要把sentinel值包含在枚举值中。虽然有时候它们对框架的开发人员来说是有帮助的,但是它们容易造成框架用户的误解。Sentinel值是用来跟踪枚举状态的值,而不属于枚举所表示的值的集合。下面的样例代码显示了一个带sentinel值的枚举,这个附加的sentinel值用来表示枚举的最后一个值,其目的是用于范围检查。在框架设计中,这是不好的做法。public enum DeskType Circular = 1, Oblong = 2, Rectangular = 3, LastValue = 3 / t

47、his sentinel value should not be herepublic void OrderDesk(DeskType desk) if (desk > DeskType.LastValue) throw new ArgumentOutOfRangeException(.); . 框架的开发人员应该用真实的枚举值来执行检查,而不应该依赖于sentinel值。public void OrderDesk(DeskType desk) if(desk > DeskType.Rectangular | desk < DeskType.Circular) throw n

48、ew ArgumentOutOfRangeException(.); . 要为简单枚举类型提供零值。可以考虑把该值称为“None”之类的东西。如果这样的值不适用于某个特定的枚举,那么应该把该枚举中最常用的默认值赋值为零。public enum Compression None = 0, Gzip, Deflate,public enum EventType Error = 0, Warning, Information, . 考虑用Int32(大多数编程语言的默认选择)作为枚举的基本实现类型,除非下面的任凭一条成立:该枚举是一个标记枚举,而你有超过32个标记,或预计今后会有更多的标记。为了更方

49、便地与需要不同大小的枚举的非托管代码进行互操作,基本的实现类型必须是Int32之外的类型。更小的底层实现类型可能会节省相当的空间。如果你预计枚举将主要用于控制流的参数,那么枚举的大小几乎不会造成什么区别。如果属于下面的情况,那么空间的节省可能相当可观:你预计枚举将被用作结构或类的字段,而且该结构或类会被频繁地实例化。你预计用户会创建包含该枚举实例的大型数组或集合。你预计该枚举的大量实例会被序列化。对于在内存中的使用,要注意的是托管对象始终是按DWORD对齐的,这样为了把枚举嵌入对象的实例中并真正能够节省空间,你还需要用多个枚举或其他小型结构来填补空缺,因为实例的总大小始终是DWORD的倍数。要

50、用复数名词或名词短语来命名标记枚举,用单数名词或名词短语来命名简单枚举。不要直接扩充System.Enum。System.Enum是一个特殊的类型,被CLR用来创建用户定义的枚举。大多数编程语言提供了相应的编程元素让你访问这项功能。例如,在C#中,enum关键字被用来定义一个枚举。2.8.1 标记枚举的设计要对标记枚举使用System.FlagsAttribute。不要把该attribute用于简单枚举。Flagspublic enum AttributeTargets .要用2的幂次方作为标记枚举的值,这样就可以通过按位或操作自由地组合它们。Flagspublic enum WatcherC

51、hangeTypes Created = 0x0002, Deleted = 0x0004, Changed = 0x0008, Renamed = 0x0010,考虑为常用的标记组合提供特殊的枚举值。位操作是一个高级概念,对简单的任务来说应该不是必需的。FileAccess.ReadWrite就是这样的一个例子。Flagspublic enum FileAccess Read = 1, Write = 2, ReadWrite = Read | Write, 避免让创建的标记枚举包含某些无效的组合。System.Reflection.BindingFlags枚举就是这种错误设计的一个例子。该

52、枚举试图表示许多不同的概念,比如可见性、静态性、成员类型等等。Flagspublic enum BindingFlags Instance, Static, NonPublic, Public, CreateInstance, GetField, SetField, GetProperty, SetProPerty, InvokeMethod, .某些枚举的组合是无效的。例如,Type.GetMembers方法以这个枚举为参数,但是该方法的文档警告用户:“为了得到返回值,你必须指定BindingFlags.Instance或BindingFlags.Static。”类似的警告对该枚举的其他一些

53、值也同样适用。如果你的枚举存在这个问题,那么你应该把该枚举的值分成两个或更多个枚举或其他类型。例如,刚才提到的反射API可以被更好地设计成下面这样:Flagspublic enum Visibilities Public,NonPublic,Flagspublic enum MemberScopes Instance,Static,Flagspublic enum MemberKinds constructor, Field, PropertyGetter, PropertySetter, Method,public class Type public MemberInfo GetMembers (MemberKinds members, Visibilities visibility, MemberScopes scope);避免把零用作标记枚举的值,除非该值表示“所有标记都被清除”,而且按下一条规范进行了适当的命名。下面的例子显示了一个常见的实现方法,程序员们用它来判断一个标记是否被设

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论