##命名准则##
#标识符
标识符中每个单词的首字母大写,不要使用下划线来区分词,或在标识符中的任何位置使用下划线
1.PascalCasing: 对于包含多个单词的所有公共成员、类型和命名空间名称,请使用PascalCasing
2.camelCasing: 使用camelCasing作为参数名称
✔️选择易于阅读的标识符名称: 属性的HorizontalAlignment可读性比更强AlignmentHorizontal
✔️提高可读性比简洁: 属性名称CanScrollHorizontally比ScrollableX(对X轴)的模糊引用更好
✔️确实使用有语义的名称: 例如,GetLength是比更好的名称GetInt
转换为的方法Int64应命名为ToInt64,而不是ToLong(因为Int64是特定于c#的别名)
❌不要假设所有编程语言都区分大小写
❌不要使用下划线、连字符或任何其他非字母数字字符
❌不要使用匈牙利表示法
❌避免使用与广泛使用的编程语言的关键字冲突的标识符
❌不要使用缩写或缩写作为标识符名称的一部分:例如,使用GetWindow而不是GetWin
❌不要使用未被广泛接受的任何首字母缩写,甚至在必要时才使用
#命名现有Api的新版本
✔️使用类似于旧API的名称
✔️确实更喜欢添加后缀(而非前缀)来指示现有API的新版本
✔️考虑使用全新但有意义的标识符,而不是添加后缀或前缀
✔️使用数字后缀来指示现有API的新版本,尤其是如果API的现有名称是有意义的唯一名称
(例如,如果它是行业标准),并且(或更改名称)添加任何有意义的后缀,则不是合适的选择
❌不要使用标识符的"Ex"(或类似的)后缀来区分它与早期版本的同一API
#程序集和DLL的名称 <Company>.<Component>.dll
程序集和DLL的名称不必与命名空间名称对应,但在命名程序集时遵循命名空间名称是合理的,
要基于程序集中包含的命名空间的公共前缀来命名DLL
例如:Litware.Controls.dll
#命名空间的名称 <Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
示例:Fabrikam.MathLitware.Security
✔️使用公司名称作为命名空间名称的前缀,以防不同公司的命名空间具有相同的名称
✔️在命名空间名称的第二级使用稳定的独立于版本的产品名称
✔️使用PascalCasing,并使用句点分隔命名空间组件(例如,Microsoft.Office.PowerPoint).
如果品牌采用nontraditional大小写,则应遵循品牌定义的大小写,即使它与常规命名空间大小写不符
✔️考虑在适当的情况下使用复数命名空间名称
例如,请使用System.Collections而不是System.Collection
品牌名称和首字母缩写是此规则的例外情况.例如,请使用System.IO而不是System.IOs
❌不要使用组织层次结构作为命名空间层次结构中的名称的基础,因为公司内的组名通常是短期的.围绕一组相关技术组织命名空间的层次结构
❌命名空间和该命名空间中的类型不要使用相同的名称
#命名空间和类型名称冲突
❌不要引入泛型类型名称Element,例如:NodeLog和Message
为避免不同类别的命名空间的类型名称冲突,有一些特定的准则:
1.应用程序模型命名空间
属于单个应用程序模型的命名空间经常一起使用,但几乎不能与其他应用程序模型的命名空间一起使用,如System.Windows*System.Web.UI*
❌不要为单个应用程序模型中的命名空间中的类型指定相同的名称
2.基础结构命名空间
此组包含在开发常见应用程序期间很少导入的命名空间.例如,.Design命名空间主要在开发编程工具时使用.
避免与这些命名空间中的类型冲突并不重要
3.核心命名空间
核心命名空间包括所有System命名空间(不包括应用程序模型的命名空间和基础结构命名空间)
❌不要提供会与核心命名空间中的任何类型冲突的类型名称
4.技术命名空间组
此类别包括的前两个命名空间节点相同的所有命名空间(<Company>.<Technology>*,例如Microsoft.Build.Utilities和Microsoft.Build.Tasks
❌不要分配会与单个技术中的其他类型冲突的类型名称
❌请勿引入技术命名空间和应用程序模型命名空间中的类型之间的类型名称冲突(除非该技术不打算用于应用程序模型)
#类、结构和接口的名称PascalCasing
✔️使用PascalCasing将类和结构命名为名词或名词短语
这区分了方法中的类型名称,这些类型名为带有谓词短语
✔️利用形容词短语或偶尔用名词或名词短语来命名接口
应很少使用名词和名词短语,它们可能会指示该类型应为抽象类,而不是接口
✔️考虑用基类的名称结束派生类的名称
在应用此准则时使用合理的判断非常重要;例如,Button类是一种Control事件,但Control它的名称中没有显示
✔️使用字母I来为接口名称加上前缀,以指示该类型是接口
例如,IComponent(描述性名词),ICustomAttributeProvider(名词短语),
IPersistable(形容词)是适当的接口名称.对于其他类型名称,请避免缩写形式
✔️确保在定义类接口对(其中类是接口的标准实现)时,接口名称上的"I"前缀仅有不同的名称
❌不要为类名称指定前缀(例如,"C")
#泛型类型参数的名称
✔️使用描述性名称命名泛型类型参数,除非单个字母名称完全一目了然,并且描述性名称不会添加值
✔️考虑使用T作为具有一个单字母类型参数的类型的类型参数名称
✔️在中为描述性类型参数名称加上前缀T. public interface ISessionChannel<TSession>where TSession:ISession
✔️考虑,指示对参数名称中的类型参数施加的约束.例如,可以调用约束为的参数ISession TSession
#命名枚举
应遵循标准类型命名规则PascalCasing
✔️为枚举使用单数类型名称,除非其值为位域
✔️对将位域作为值的枚举使用复数类型名称,也称为标志枚举
❌不要在枚举类型名称中使用"Enum"后缀.
❌不要在枚举类型名称中使用"标记"或"标志"后缀.
❌不要在枚举值名称上使用前缀(例如,将"ad"用于ADO枚举,使用"rtf"进行丰富文本枚举等)
#方法的名称
✔️为谓词或谓词短语指定方法名称
#属性的名称
✔️使用名词、名词短语或形容词名称属性
✔️使用一个复数短语来描述集合中的项,而不是使用后跟"List"或"Collection"的短语来命名集合属性
✔️使用赞成短语(,CanSeek而不是)来命名布尔属性CantSeek.或者,还可以在布尔属性前面添加"Is"、"Can"或"has"前缀,但前提是在它添加值的位置
✔️考虑为属性提供与其类型相同的名称
❌没有与"Get"方法的名称相匹配的属性,如以下示例中所示
publicstringTextWriter{get{...}set{...}}
publicstringGetTextWriter(intvalue){...}
此模式通常意味着该属性事实上是一种方法
#事件的名称
✔️使用动词或动词短语来命名事件.示例包括Clicked、Painting和DroppedDown
✔️使用现有的和过去的时态为事件名称提供前后的概念
例如,在窗口关闭前引发的关闭事件可命名为Closing,而在窗口关闭后后引发的关闭事件可命名为Closed
✔️命名事件处理程序(使用"EventHandler"后缀的事件类型)委托,如下面的示例中所示:
public delegate void ClickedEventHandler(object sender,Clicked EventArgse);
✔️确实要sendere在事件处理程序中使用两个名为和的参数
sender参数表示引发事件的对象.sender参数的类型通常是object,即使可以使用更具体的类型
✔️用"EventArgs"后缀命名事件参数类
❌不要使用"Before"或"After"前缀或postfixes来指示前和后事件.使用现在时和过去时
#字段的名称
字段命名准则适用于静态公开字段和受保护的字段.原则不涉及内部和专用字段,
而成员设计准则不允许使用公开字段或受保护的实例字段
✔️在字段名称中使用PascalCasing
❌不要对字段名称使用前缀,例如,请勿使用"g_"或"s_"来指示静态字段
#命名参数
✔️在参数名称中使用camelCasing.
✔️使用描述性参数名称
✔️考虑使用基于参数含义而不是参数类型的名称
#命名运算符重载参数
left right如果参数没有任何意义,✔️确实要使用和进行二元运算符重载参数名称.
对于参数,✔️确实使用value一元运算符重载参数名称.
✔️考虑运算符重载参数有意义的名称,如果这样做会增加重要值
❌不要对运算符重载参数名称使用缩写或数值索引
#命名资源
由于可以通过某些对象来引用可本地化的资源,就像它们是属性一样,因此资源的命名准则与属性准则类似
✔️在资源键中使用PascalCasing.
✔️提供描述性而不是短标识符.
✔️在命名资源中仅使用字母数字字符和下划线.
✔️对异常消息资源使用以下命名约定.
资源标识符应为异常类型名称和异常的简短标识符:
ArgumentExceptionIllegalCharacters
ArgumentExceptionInvalidName
ArgumentExceptionFileNameIsMalformed
❌不要使用主要CLR语言的特定于语言的关键字
#常见类型的名称
System.Attribute ✔️将后缀"Attribute"添加到自定义特性类的名称中
System.Delegate ✔️将后缀"EventHandler"添加到在事件中使用的委托的名称
✔️将后缀"Callback"添加到作为事件处理程序使用的委托的名称
❌不要将后缀"Delegate"添加到委托
System.EventArgs ✔️添加后缀"EventArgs"
System.Enum ❌不要从此类派生;改为使用您的语言支持的关键字;例如,在c#中,使用enum关键字
❌不要添加后缀"Enum"或"标志"
System.Exception ✔️添加后缀"Exception"
IDictionary|IDictionary<TKey,TValue>
. ✔️添加后缀"Dictionary".请注意,IDictionary是一种特定类型的集合,
但是此准则优先于下面的更常见的集合原则
IEnumerable|ICollection|IList|IEnumerable<T>|ICollection<T>|IList<T>
✔️添加后缀"Collection"
System.IO.Stream ✔️添加后缀"Stream"
##类型设计准则##
从CLR的角度来看,只有两种类型:引用类型和值类型
类 :
是引用类型的常规用例基类和抽象类是与扩展性相关的特殊逻辑组
接口 :
是可由引用类型和值类型实现的类型可充当引用类型和值类型的多态层次结构的根
结构 :
是值类型的常规用例,应为小型简单类型保留,类似于语言基元
枚举 :
是值类型的一种特例,用于定义短值集,如星期几、控制台颜色等
静态类 :
是旨在作为静态成员容器的类型.它们通常用于提供其他操作的快捷方式
委托、异常、特性、数组和集合都是专用于特定用途的引用类型的特例
✔️请务必确保每个类型都是一组定义完善的相关成员,而不只是一个随机的无关功能集合
#在类和结构之间选择
将类型设计为作为类(引用类型)还是作为结构()值类型
引用类型分配复制引用,而值类型分配则复制整个值
✔️考虑定义结构而不是类的实例,如果该类型的实例较小且通常为短生存期,或者通常嵌入到其他对象中
❌避免定义结构,除非该类型具有以下所有特性:
1.它以逻辑方式表示单个值,与int double等的基元类型类似
2.它的实例大小为16字节
3.它是不可变的
4.它不需要频繁装箱
在所有其他情况下,应将类型定义为类
#抽象类设计
✔️请务必在抽象类中定义一个受保护的或内部的构造函数
受保护的构造函数更常见,在创建子类型时,它仅允许基类进行自己的初始化.
内部构造函数可用于将抽象类的具体实现限制为定义该类的程序集
✔️请务必提供至少一种从你交付的每个抽象类继承的具体类型
这样做有助于验证抽象类的设计
❌请勿在抽象类型中定义公共或受保护的内部构造函数
只有在用户需要创建类型的实例时,构造函数才应该是公共的.由于你无法创建抽象类型的实例,
因此具有公共构造函数的抽象类型设计不正确,会引起用户的误解
#静态类设计
静态类定义为仅包含静态成员
静态类是纯面向对象的设计与简单性之间的折衷
✔️请务必要少使用静态类.静态类应该只用作框架的面向对象核心的支持类
✔️如果你的编程语言没有对静态类的内置支持,请务必将静态类声明为密封的且抽象的,并添加一个专用实例构造函数
❌请勿将静态类视为杂项桶
❌请勿在静态类中声明或替代实例成员
#接口设计
允许类型实现一个或多个接口以及从基类继承
例如,IDisposable是一个接口,该接口允许类型独立于它们要参与的任何其他继承层次结构来支持可处置性
适合定义接口的另一种情况是创建可由多种类型(包括某些值类型)支持的通用接口.值类型不能从ValueType以外的类型继承,
但它们可以实现接口,因此,使用接口