# CSharp-Language-Specification **Repository Path**: aoangocc/CSharp-Language-Specification ## Basic Information - **Project Name**: CSharp-Language-Specification - **Description**: C# 编码规范 - **Primary Language**: C# - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 3 - **Created**: 2021-07-03 - **Last Updated**: 2022-12-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C# 编码规范 [1 前言](#user-content-1-%E5%89%8D%E8%A8%80) [2 代码风格](#user-content-2-%E4%BB%A3%E7%A0%81%E9%A3%8E%E6%A0%BC)   [2.1 文件](#user-content-21-%E6%96%87%E4%BB%B6)   [2.2 结构](#user-content-22-%E7%BB%93%E6%9E%84)     [2.2.1 缩进](#user-content-221-%E7%BC%A9%E8%BF%9B)     [2.2.2 空格](#user-content-222-%E7%A9%BA%E6%A0%BC)     [2.2.3 换行](#user-content-223-%E6%8D%A2%E8%A1%8C)     [2.2.4 语句](#user-content-224-%E8%AF%AD%E5%8F%A5)   [2.3 命名](#user-content-23-%E5%91%BD%E5%90%8D)   [2.4 注释](#user-content-24-%E6%B3%A8%E9%87%8A)     [2.4.1 单行注释](#user-content-241-%E5%8D%95%E8%A1%8C%E6%B3%A8%E9%87%8A)     [2.4.2 多行注释](#user-content-242-%E5%A4%9A%E8%A1%8C%E6%B3%A8%E9%87%8A)     [2.4.3 摘要注释](#user-content-243-%E6%91%98%E8%A6%81%E6%B3%A8%E9%87%8A)     [2.4.4 细节注释](#user-content-244-%E7%BB%86%E8%8A%82%E6%B3%A8%E9%87%8A) ## 1 前言 本文档的目标是使 C# 代码风格保持一致,容易被理解和被维护,应尽量遵循本文档的约定。 ## 2 代码风格 ### 2.1 文件 ##### [建议] 文件使用无 `BOM` 的 `UTF-8` 编码。 解释: UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。 ##### [建议] 在文件结尾处,保留一个空行。 ### 2.2 结构 #### 2.2.1 缩进 ##### [强制] 使用 `tab` 做为一个缩进层级,不允许使用空格。 ##### [强制] `switch` 下的 `case` 和 `default` 必须增加一个缩进层级。 示例: ```C# // good switch (strProcCode) { //TODO: 业务逻辑(申请、同意、拒绝、运行中撤销、同意后撤销) case "PROC0001": //请假 tuple = AskForLeaveLogic.Approval(ref input); break; case "PROC0101": //申请寝室长 tuple = SuSheLogic.DormitoryLeader(ref input); break; case "PROC0102": //申请留校 tuple = SuSheLogic.StayDormitory(ref input); break; } // bad switch (strProcCode) { //TODO: 业务逻辑(申请、同意、拒绝、运行中撤销、同意后撤销) case "PROC0001": //请假 tuple = AskForLeaveLogic.Approval(ref input); break; case "PROC0101": //申请寝室长 tuple = SuSheLogic.DormitoryLeader(ref input); break; case "PROC0102": //申请留校 tuple = SuSheLogic.StayDormitory(ref input); break; } ``` #### 2.2.2 空格 ##### [强制] 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格。 示例: ```C# var a = !arr.Count; a++; a = b + c; ``` ##### [强制] `if / for / while / switch / try / catch` 关键字后,必须有一个空格。 示例: ```C# // good if (condition) { } while (condition) { } // bad if(condition) { } while(condition) { } ``` ##### [强制] 方法声明、方法调用中,方法名和 `(` 之间不允许有空格。 示例: ```C# // good public static APOutput CreateProcessInstance(APInput input) { } var output = ProcessLogic.CreateProcessInstance(input); // bad public static APOutput CreateProcessInstance (APInput input) { } var output = ProcessLogic.CreateProcessInstance (input); ``` ##### [强制] `,` 和 `;` 前不允许有空格。如果不位于行尾,`,` 和 `;` 后必须跟一个空格。 示例: ```C# // good CallFunc(a, b); // bad CallFunc(a , b) ; ``` ##### [强制] 在方法调用、方法声明、括号表达式、属性访问、`if / for / while / switch / catch` 等语句中,`()` 和 `[]` 内紧贴括号部分不允许有空格。 示例: ```C# // good CallFunc(param1, param2, param3); Save(list[indexes[i]]); needIncream && (variable += increament); if (num > list.Count) { } while (len--) { } // bad CallFunc( param1, param2, param3 ); Save( list[ indexes[ i ] ] ); needIncreament && ( variable += increament ); if ( num > list.Count ) { } while ( len-- ) { } ``` ##### [强制] 行尾不得有多余的空格。 #### 2.2.3 换行 ##### [强制] 每个独立语句结束后必须换行。 ##### [强制] 用作代码块起始的左花括号 `{` 前必须换行。 示例: ```C# // good if (condition) { } while (condition) { } public static APOutput CreateProcessInstance(APInput input) { } // bad if (condition) { } while (condition) { } public static APOutput CreateProcessInstance(APInput input) { } ``` ##### [强制] 每行不得超过 `120` 个字符。 解释: 超长的不可分割的代码允许例外,比如复杂的正则表达式。长字符串不在例外之列。 ##### [强制] 运算符处换行时,运算符必须在新行的行首。 示例: ```C# // good if (user.IsAuthenticated() && user.IsInRole('admin') && user.HasAuthority('add-admin') || user.HasAuthority('delete-admin')) { // Code } var result = number1 + number2 + number3 + number4 + number5; // bad if (user.IsAuthenticated() && user.IsInRole('admin') && user.HasAuthority('add-admin') || user.HasAuthority('delete-admin')) { // Code } var result = number1 + number2 + number3 + number4 + number5; ``` ##### [建议] 不同行为或逻辑的语句集,使用空行隔开,更易阅读。 示例: ```C# // 仅为按逻辑换行的示例,不代表SetValue的最优实现 public static void SetValue(JObject obj, string key, JToken value) { if (obj == null) { return; } obj[key] = value; } ``` ##### [建议] 对于 `if...else...`、`try...catch...finally` 等语句,推荐使用在 `}` 号后添加一个换行 的风格,使代码层次结构更清晰,阅读性更好。 示例: ```C# if (condition) { // some statements; } else { // some statements; } try { // some statements; } catch (ex) { // some statements; } ``` #### 2.2.4 语句 ##### [强制] 在 `if / else / for / do / while` 语句中,即使只有一行,也不得省略块 `{...}`。 示例: ```C# // good if (condition) { CallFunc(); } // bad if (condition) CallFunc(); if (condition) CallFunc(); ``` ### 2.3 命名 ##### [强制] `private` 修饰的 `变量` 使用 `camel命名法`,并加 `下划线`。 示例: ```C# private int _count = 0; ``` ##### [强制] `private static` 修饰的 `变量` 使用 `camel命名法`,并加 `下划线`。 示例: ```C# private static int _count = 0; ``` ##### [强制] `private readonly` 修饰的 `变量` 使用 `camel命名法`,并加 `下划线`。 示例: ```C# private readonly int _count = 0; ``` ##### [强制] `private static readonly` 修饰的 `变量` 使用 `Pascal命名法`。 示例: ```C# private static readonly int Count = 0; ``` ##### [强制] 只要有 `public` 修饰的 `变量` 就使用 `Pascal命名法`。 示例: ```C# public int Count = 0; ``` ##### [强制] `局部变量` 使用 `camel命名法`。 示例: ```C# var count = 0; ``` ##### [强制] `类中的常量` 使用 `Pascal命名法`。 示例: ```C# private const int Count = 0; ``` ##### [强制] `全局常量` 使用 `全部字母大写,单词间下划线分隔` 的命名方式。 示例: ```C# public const SYNC_COUNT = 0; ``` ##### [强制] `方法` 使用 `Pascal命名法`。 示例: ```C# public static void Sync() { } ``` ##### [强制] 方法的 `参数` 使用 `camel命名法`。 示例: ```C# public static void Sync(int count) { } ``` ##### [强制] `类` 使用 `Pascal命名法`。 示例: ```C# public class Logic { } ``` ##### [强制] `枚举变量` 使用 `Pascal命名法`,`枚举的属性` 使用 `Pascal命名法` 或 `全部字母大写,单词间下划线分隔` 的命名方式。 示例: ```C# /// /// 审批状态 /// public enum APProcessStatus { /// /// 新创建 /// NEW = 0, /// /// 运行中 /// RUNNING = 1, /// /// 取消 /// CANCELED = 2, /// /// 被终止 /// TERMINATED = 3, /// /// 完成 /// COMPLETED = 4 } ``` ##### [强制] `命名空间` 使用 `Pascal命名法`。 示例: ```C# namespace WebYKT.Model.Enums { } ``` ##### [强制] 由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。 示例: ```C# public static string XMLParser(string strXML) { } public static void InsertXML(string strXML) { } var httpRequest = new HTTPRequest(); ``` ##### [强制] `类名` 使用 `名词`。 示例: ```C# public class Logic { } ``` ##### [建议] `方法名` 使用 `动宾短语`。 示例: ```C# public static void InsertXML(string strXML) { } ``` ##### [建议] `async` 修饰的 `方法名` 加后缀 `Async` 。 示例: ```C# public static async Task InsertXMLAsync(string strXML) { } ``` ##### [建议] `bool` 类型的变量使用 `is` 或 `has` 开头。 示例: ```C# var isReady = false; var hasMoreCommands = false; ``` ### 2.4 注释 #### 2.4.1 单行注释 ##### [强制] 必须独占一行。`//` 后跟一个空格,缩进与下一行被注释说明的代码一致。 #### 2.4.2 多行注释 ##### [建议] 避免使用 `/*...*/` 这样的多行注释。有多行注释内容时,使用多个单行注释。 #### 2.4.3 摘要注释 ##### [强制] 为了便于代码阅读,以下内容必须包含以 `` 形式的摘要注释中。 解释: 1. 类 2. 方法或方法 3. 类属性 4. 事件 5. 全局变量 6. 常量 ```C# /// /// 请求 /// /// 地址 /// 返回内容 public static string Request(string strUri) { // …… } ``` #### 2.4.4 细节注释 对于内部实现、不容易理解的逻辑说明、摘要信息等,我们可能需要编写细节注释。 ##### [建议] 细节注释遵循单行注释的格式。说明必须换行时,每行是一个单行注释的起始。 示例: ```C# public static string Request(string strUri) { // 这里对具体内部逻辑进行说明 // 说明太长需要换行 for (...) { .... } } ``` ##### [强制] 有时我们会使用一些特殊标记进行说明。特殊标记必须使用单行注释的形式。下面列举了一些常用标记: 解释: 1. TODO: 有功能待实现。此时需要对将要实现的功能进行简单说明。 2. #region #endregion: 注释其中间的代码段,或者折叠中间的代码块。注意#region和#endregion的上下换行。 ```C# #region 说明 // …… #endregion ```