团队项目开发"编码规范"之八:
代码格式检查
代码格式检查使用微软内部代码检查工具 StyleCop 版本4.3.2.1,它会根据预定义的C#代码格式的最佳实践,对源代码进行检查,并给出不符合编码风格的错误提示(版本语言英文)。
8.1 检查分类
检查规则分为7个部分,分别是
“文档规则(Documentation Rules)”
“布局规则(LayoutRules)”
“可维护性规则(Maintanability Rules)”
“命名规则(Naming Rules)”
“代码顺序规则(Ordering Rules)”
“可读性规则(Readability Rules)”
“间距规则(Spacing Rules)”
8.2 安装及使用
安装:安装程序位于附件,Install文件夹中。该软件属于Visual Studio插件,安装后在工具菜单栏中。
使用:运行该功能后,可以根据“错误列表”中的警告信息的信息Id,从帮助文件(位于附件,Document文件夹中,文件名StyleCop.chm)找到相应编码格式,进行修复。
开发文档:位于附件,Document文件夹中,文件名StyleCopSDK.chm)
对于以下情况 “是否检查”一项中为“√”的内容不能违反。
8.3 文档规则(Documentation Rules)
标识及提示 |
中文及示例 |
是否检查 |
SA1600: ElementsMustBeDocumented |
元素必须被注释 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1601: PartialElementsMustBeDocumented |
部分元素必须被注释 /// <summary> /// Documentation for the first part of Class1. /// </summary> public partial class Class1 { }
/// <summary> /// Documentation for the second part of Class1. /// </summary> public partial class Class1 { } |
√ |
SA1602: EnumerationItemsMustBeDocumented |
枚举项必须被注释 /// <summary> /// Types of animals. /// </summary> public enum Animals { /// <summary> /// Represents a dog. /// </summary> Dog,
/// <summary> /// Represents a cat. /// </summary> Cat,
/// <summary> /// Represents a horse. /// </summary> Horse } |
√ |
SA1603: DocumentationMustContainValidXml |
文档必须包含有效的XML注释 /// <summary> /// An example of badly formed Xml. /// </summa3ry> public class Example { } |
√ |
SA1604: ElementDocumentationMustHaveSummary |
文档注释必须包含Summary /// <summary> /// Represents a customer in the database. /// </summary> public class Customer { } |
√ |
SA1605: PartialElementDocumentationMustHaveSummary |
部分文档注释必须包含Summary /// <summary> /// Documentation for the first part of Class1. /// </summary> public partial class Class1 { }
/// <summary> /// Documentation for the second part of Class1. /// </summary> public partial class Class1 { } |
√ |
SA1606: ElementDocumentationMustHaveSummaryText |
文档注释Summary必须有内容 /// <summary> </summary> /// <param name="customerId">The ID of the customer to find.</param> /// <returns>The customer, or null if the customer could not be /// found.</returns> public Customer FindCustomer(int customerId) { // ... finds the customer ... } |
√ |
SA1607: PartialElementDocumentationMustHaveSummaryText |
部分文档注释Summary必须有内容 /// <summary> </summary> /// <param name="customerId">The ID of the customer to find.</param> /// <returns>The customer, or null if the customer could not be found.</returns> public Customer FindCustomer(int customerId) { // ... finds the customer ... }
修复代码 /// <summary>Attempts to locate a record for the customer with the given ID.</summary> /// <param name="customerId">The ID of the customer to find.</param> /// <returns>The customer, or null if the customer could not be found.</returns> public Customer FindCustomer(int customerId) { // ... finds the customer ... } |
√ |
SA1608: ElementDocumentationMustNotHaveDefaultSummary |
文档注释不能有默认的Summary /// <summary> /// Summary description for the Example class. /// </summary> public class Example { } |
√ |
SA1609: PropertyDocumentationMustHaveValue |
属性注释必须有值 /// <summary> /// Gets the name of the customer. /// </summary> /// <value>The name of the customer.</value> public bool Name { get { return this.name; } } |
√ |
SA1610: PropertyDocumentationMustHaveValueText |
属性注释必须有值内容 /// <summary> /// Gets the name of the customer. /// </summary> /// <value>The name of the customer.</value> public bool Name { get { return this.name; } } |
√ |
SA1611: ElementParametersMustBeDocumented |
元素的参数必须注释 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1612: ElementParameterDocumentationMustMatchElementParameters |
元素的参数注释必须与元素参数成对 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1613: ElementParameterDocumentationMustDeclareParameterName |
元素的参数注释必须定义参数名 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1614: ElementParameterDocumentationMustHaveText |
元素的参数注释必须有值 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1615: ElementReturnValueMustBeDocumented |
元素的返回值必须被注释 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1616: ElementReturnValueDocumentationMustHaveValue |
元素的返回值注释必须有值 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1617: VoidReturnValueMustNotBeDocumented |
元素空返回值不能注释 /// <summary> /// Prints the given name. /// </summary> /// <param name="firstName">The first name.</param> /// <param name="lastName">The last name.</param> public void PrintNames(string firstName, string lastName) { Console.WriteLine(firstName + " " + lastName); } |
√ |
SA1618: GenericTypeParametersMustBeDocumented |
泛型参数必须被注释 /// <summary> /// A sample generic class. /// </summary> /// <typeparam name="S">The first generic type parameter.</typeparam> /// <typeparam name="T">The second generic type parameter.</typeparam> public class Class1<S, T> { } |
√ |
SA1619: GenericTypeParametersMustBeDocumentedPartialClass |
泛型参数在部分类中必须被注释 /// <summary> /// A sample generic class. /// </summary> /// <typeparam name="S">The first generic type parameter.</typeparam> /// <typeparam name="T">The second generic type parameter.</typeparam> public class Class1<S, T> { } |
√ |
SA1620: GenericTypeParameterDocumentationMustMatchTypeParameters |
泛型参数注释必须与参数类型对应 /// <summary> /// A sample generic class. /// </summary> /// <typeparam name="S">The first generic type parameter.</typeparam> /// <typeparam name="T">The second generic type parameter.</typeparam> public class Class1<S, T> { } |
√ |
SA1621: GenericTypeParameterDocumentationMustDeclareParameterName |
泛型参数注释必须定义参数名 /// <summary> /// A sample generic class. /// </summary> /// <typeparam name="S">The first generic type parameter.</typeparam> /// <typeparam name="T">The second generic type parameter.</typeparam> public class Class1<S, T> { } |
√ |
SA1622: GenericTypeParameterDocumentationMustHaveText |
泛型参数注释必须有内容 /// <summary> /// A sample generic class. /// </summary> /// <typeparam name="S">The first generic type parameter.</typeparam> /// <typeparam name="T">The second generic type parameter.</typeparam> public class Class1<S, T> { } |
√ |
SA1623: PropertySummaryDocumentationMustMatchAccessors |
属性摘要文档必须和访问者对应 (参考帮助文档) |
√ |
SA1624: PropertySummaryDocumentationMustOmitSetAccessorWithRestricedAccess |
属性摘要文档必须必须省略设置访问器约束访问 (参考帮助文档) |
√ |
SA1625: ElementDocumentationMustNotBeCopiedAndPasted |
元素注释不能被拷贝和粘贴 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1626: SingleLineCommentsMustNotUseDocumentationStyleSlashes |
单行注释不能使用斜线样式 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">Part of the name.</param> /// <param name="lastName">Part of the name.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { A legal comment beginning with two slashes: // Join the names together. string fullName = firstName + " " + lastName;
An illegal comment beginning with three slashes: /// Trim the name. fullName = fullName.Trim();
A line of commented-out code beginning with four slashes: ////fullName = asfd;
return fullName; } |
√ |
SA1627: DocumentationTextMustNotBeEmpty |
注释内容不能为空 /// <summary> /// Joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName"> </param> /// <param name="lastName">Part of the name.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { ... } |
√ |
SA1628: DocumentationTextMustBeginWithACapitalLetter |
注释内容首字母必须大写 /// <summary> /// joins a first name and a last name together into a single string. /// </summary> /// <param name="firstName">The first name.</param> /// <param name="lastName">The last name.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { ... } |
√ |
SA1629: DocumentationTextMustEndWithAPeriod |
注释内容必须用句号结尾 /// <summary> /// Joins a first name and a last name together into a single string /// </summary> /// <param name="firstName">The first name.</param> /// <param name="lastName">The last name.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { ... } |
√ |
SA1630: DocumentationTextMustContainWhitespace |
注释内容单词之间必须包含空白符 /// <summary> /// Joinsnames /// </summary> /// <param name="firstName">First</param> /// <param name="lastName">Last</param> /// <returns>Name</returns> public string JoinNames(string firstName, string lastName) { ... } |
|
SA1631: DocumentationTextMustMeetCharacterPercentage |
注释内容必须满足字符比例特殊字符不能过多 /// <summary> /// @)$(*A name-------- /// </summary> public class Name { ... } |
|
SA1632: DocumentationTextMustMeetMinimumCharacterLength |
注释内容必须满足小写字符长度 /// <summary> /// A name /// </summary> public class Name { ... } |
√ |
SA1633: FileMustHaveHeader |
文件必须有文件头部注释 //----------------------------------------------------------------------- // <copyright file="NameOfFile.cs" company="CompanyName"> // Company copyright tag. // </copyright> //-----------------------------------------------------------------------
For example, a file called Widget.cs from a fictional company called Sprocket Enterprises should contain a file header similar to the following: //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //-----------------------------------------------------------------------
The dashed lines at the top and bottom of the header are not strictly necessary, so the header could be written as: // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright>
It is possible to add additional tags, although they will not be checked or enforced by StyleCop: //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> // <author>John Doe</author> //----------------------------------------------------------------------- |
√ |
SA1634: FileHeaderMustShowCopyright |
文件头部注释必须显示版权信息标识 //----------------------------------------------------------------------- // <Tag>A file header which does not contain a copyright tag</Tag> //-----------------------------------------------------------------------
A file header should include a copyright tag, as follows: //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1635: FileHeaderMustHaveCopyrightText |
文件头部注释必须有版权信息表示内容 //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // </copyright> //-----------------------------------------------------------------------
A file header should include copyright text, as follows: //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1636: FileHeaderMustContainFileName |
文件头部注释必须包含文件名 //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="My Company"> // Custom company copyright tag. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1637: FileHeaderMustContainFileName |
文件头部注释必须包含文件名 //----------------------------------------------------------------------- // <copyright company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //-----------------------------------------------------------------------
//----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1638: FileHeaderFileNameDocumentationMustMatchFileName |
文件头部注释文件名注释必须与文件名对应 //----------------------------------------------------------------------- // <copyright file="File2.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //-----------------------------------------------------------------------
A violation of this rule would occur, since the file tag does not contain the name of the file. The header should be written as: //----------------------------------------------------------------------- // <copyright file="File1.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1639: FileHeaderMustHaveSummary |
文件头部注释不许有摘要 //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //-----------------------------------------------------------------------
If this rule is enabled, the file header should contain a summary tag. For example: //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> // <summary>Defines the Widget class.</summary> //----------------------------------------------------------------------- |
√ |
SA1640: FileHeaderMustHaveValidCompanyText |
文件头部注释必须有正确的公司信息 //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="Sprocket Enterprises"> // Copyright (c) Sprocket Enterprises. All rights reserved. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1641: FileHeaderCompanyNameTextMustMatch |
文件头部注释公司内容必须对应 //----------------------------------------------------------------------- // <copyright file="Widget.cs" company="My Company"> // Custom company copyright tag. // </copyright> //----------------------------------------------------------------------- |
√ |
SA1642: ConstructorSummaryDocumentationMustBeginWithStandardText |
构造器的Summary注释必须由标准内容开始 (参考帮助文档) |
√ |
SA1643: DestructorSummaryDocumentationMustBeginWithStandardText |
析构器的Summary注释必须由标准内容开始 /// <summary> /// Initializes a new instance of the <see cref="Customer`1"/> class. /// </summary> public Customer() { }
/// <summary> /// Initializes a new instance of the <see cref="Customer{T}"/> class. /// </summary> public Customer() { } |
√ |
SA1644: DocumentationHeadersMustNotContainBlankLines |
注释头部不能包含空白行 /// <summary> /// <para> /// Joins a first name and a last name together into a single string. /// </para><para> /// Uses a simple form of string concatenation. /// </para> /// </summary> /// <param name="firstName">The first name to join.</param> /// <param name="lastName">The last name to join.</param> /// <returns>The joined names.</returns> public string JoinNames(string firstName, string lastName) { return firstName + " " + lastName; } |
√ |
SA1645: IncludedDocumentationFileDoesNotExist |
导入的文档注释文件不存在 ///<include file="IncludedDocumentation.xml" path="root/EnabledMethodDocs" /> public bool Enabled(bool true) { }
|
√ |
SA1646: IncludedDocumentationXPathDoesNotExist |
导入的文档注释的XPath不存在 ///<include file="IncludedDocumentation.xml" path="root/EnabledMethodDocs" /> public bool Enabled(bool true) { } |
√ |
SA1647: IncludeNodeDoesNotContainValidFileAndPath |
导入的结点不存在正确的文件和路径 ///<include file="IncludedDocumentation.xml" path="root/EnabledMethodDocs" /> public bool Enabled(bool true) { } |
√ |
8.4 布局规则(LayoutRules)
标识及提示 |
中文及示例 |
是否检查 |
SA1500: CurlyBracketsForMultiLineStatementsMustNotShareLine |
当多行代码使用{}时"{" 与 "}"必须单独占一行 |
√ |
SA1501: StatementMustNotBeOnSingleLine |
{}不能与代码写在同一行 |
√ |
SA1502: ElementMustNotBeOnSingleLine |
元素定义不能在同一行 |
√ |
SA1503: CurlyBracketsMustNotBeOmitted |
{}符号不能被省略 |
√ |
SA1504: AllAccessorMustBeMultiLineOrSingleLine |
所有的访问器代码,必须是多行或一行(不能Get多行,Set单行) |
√ |
SA1505: OpeningCurlyBracketsMustNotBeFollowedByBlankLine |
{ 符号下面不能跟空行 |
√ |
SA1506: ElementDocumentationHeadersMustNotBeFollowedByBlankLine |
元素注释头部不能跟空行 |
√ |
SA1507: CodeMustNotContainMultipleBlankLinesInARow |
代码不能包含连续的多个空行 |
√ |
SA1508: ClosingCurlyBracketsMustNotBePrecededByBlankLine |
} 符号上方不能有空行 |
√ |
SA1509: OpeningCurlyBracketsMustNotBePrecedededByBlankLine |
{ 符号与代码之间不能有空行 |
√ |
SA1510: ChainedStatementBlocksMustNotBePrecededByBlankLine |
使用 {} 符号并且连接的代码之间不能有空行 |
√ |
SA1511: WhileDoFooterMustNotBePrecededByBlankLine |
Do While代码之间不能有空行 |
√ |
SA1512: SingleLineCommentsMustNotBeFollowedByBlankLine |
单行注释与代码之间不能有空行 |
√ |
SA1513: ClosingCurlyBracketMustBeFollowedByBlankLine |
} 符号后面必须有空行 |
√ |
SA1514: ElementDocumentationHeaderMustBePrecededByBlankLine |
元素注释头部必须加空行 |
√ |
SA1515: SingleLineCommentMustBePrecededByBlankLine |
单行注释前面必须加空行 |
√ |
SA1516: ElementsMustBeSeparatedByBlankLine |
元素必须用空行分隔 |
√ |
8.5 可维护性规则(Maintanability Rules)”
标识及提示 |
中文及示例 |
是否检查 |
SA1300: ElementMustBeginWithUpperCaseLetter |
元素必须首字母大写 |
√ |
SA1301: ElementMustBeginWithLowerCaseLetter |
元素必须首字母小写 |
√ |
SA1302: InterfaceNamesMustBeginWithI |
命名接口必须以I开头 |
√ |
SA1303: ConstFieldNamesMustBeginWithUpperCaseLetter |
常量字段命名必须首字母大写 |
√ |
SA1304: NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter |
非私有只读字段必须首字母大写 |
√ |
SA1305: FieldNamesMustNotUseHungarianNotation |
字段名不能使用匈牙利命名法 |
√ |
SA1306: FieldNamesMustBeginWithLowerCaseLetter |
字段名必须首字母小写 |
√ |
SA1307: AccessibleFieldsMustBeginWithUpperCaseLetter |
可访问字段必须首字母大写 |
√ |
SA1308: VariableNamesMustNotBePrefixed |
变量名不能加前缀 |
√ |
SA1309: FieldNamesMustNotBeginWithUnderscore |
字段名不能以"_"开头 |
√ |
SA1310: FieldNamesMustNotContainUnderscore |
字段名不能包含"_" |
√ |