Skip to Content
C#格式化指南

格式化指南

命名规则

命名规则遵循 Microsoft 的 C# 命名指南 。 在 Microsoft 命名指南未作规定的地方(例如私有变量和局部变量),规则取自 CoreFX C# 编码指南 

规则摘要:

代码

  • 类(Class)、方法(Method)、枚举(Enum)、公共字段(Public Field)、公共属性(Public Property)、 命名空间(Namespace)的名称:使用 PascalCase
  • 局部变量(Local Variable)、参数(Parameter)的名称:使用 camelCase
  • 私有(Private)、受保护(Protected)、内部(Internal)以及受保护内部(Protected Internal) 的字段和属性的名称:使用 _camelCase
  • 命名约定不受 const、static、readonly 等修饰符的影响。
  • 在大小写方面,“单词”是指不含内部空格的任何内容,包括缩略词。例如,使用 MyRpc 而不是 MyRPC
  • 接口(Interface)名称以 I 开头,例如 IInterface

文件

  • 文件名和目录名使用 PascalCase,例如 MyFile.cs
  • 尽可能使文件名与文件中主类的名称一致,例如 MyClass.cs
  • 通常,每个文件只包含一个核心类。

组织结构

  • 修饰符(Modifier)按以下顺序排列:public protected internal private new abstract virtual override sealed static readonly extern unsafe volatile async
  • 命名空间的 using 声明放在最顶部,位于任何命名空间之前。using 导入顺序按字母排列,但 System 导入始终排在最前面。
  • 类成员排序:
    • 按以下顺序对类成员进行分组:
      • 嵌套类(Nested Class)、枚举(Enum)、委托(Delegate)和事件(Event)。
      • 静态(Static)、常量(Const)和只读(Readonly)字段。
      • 字段(Field)和属性(Property)。
      • 构造函数(Constructor)和终结器(Finalizer)。
      • 方法(Method)。
    • 在每个分组内,元素应按以下顺序排列:
      • Public。
      • Internal。
      • Protected internal。
      • Protected。
      • Private。
    • 尽可能将接口实现放在一起。

空白规则

源自 Google Java 风格。

  • 每行最多一条语句。
  • 每条语句最多一个赋值。
  • 缩进使用 2 个空格,不使用制表符(Tab)。
  • 列宽限制:100。
  • 左花括号前不换行。
  • 右花括号和 else 之间不换行。
  • 即使花括号是可选的也要使用。
  • if/for/while 等关键字后以及逗号后加空格。
  • 左圆括号后和右圆括号前不加空格。
  • 一元运算符(Unary Operator)与其操作数之间不加空格。其他所有运算符与每个操作数之间加一个空格。
  • 换行规则源自 Google C++ 风格指南,并针对与 Microsoft C# 格式化工具的兼容性做了少量修改:
    • 通常,续行缩进 4 个空格。
    • 带花括号的换行(例如列表初始化器、Lambda 表达式、对象初始化器等)不算作续行。
    • 对于函数定义和调用,如果参数无法全部放在一行,应将它们拆分到多行, 每个后续行与第一个参数对齐。如果空间不足,参数可以放在后续行并缩进 4 个空格。下面的代码示例对此进行了说明。

示例

using System; // `using` 放在最顶部,位于 // 命名空间之外。 namespace MyNamespace { // 命名空间使用 PascalCase。 // 命名空间内缩进。 public interface IMyInterface { // 接口以 'I' 开头 public int Calculate(float value, float exp); // 方法使用 PascalCase // ...逗号后加空格。 } public enum MyEnum { // 枚举使用 PascalCase。 Yes, // 枚举值使用 PascalCase。 No, } public class MyClass { // 类使用 PascalCase。 public int Foo = 0; // 公共成员变量使用 // PascalCase。 public bool NoCounting = false; // 鼓励使用字段初始化器。 private class Results { public int NumNegativeResults = 0; public int NumPositiveResults = 0; } private Results _results; // 私有成员变量使用 // _camelCase。 public static int NumTimesCalled = 0; private const int _bar = 100; // const 不影响命名 // 约定。 private int[] _someTable = { // 容器初始化器使用 2 个 2, 3, 4, // 空格缩进。 } public MyClass() { _results = new Results { NumNegativeResults = 1, // 对象初始化器使用 2 个 NumPositiveResults = 1, // 空格缩进。 }; } public int CalculateValue(int mulNumber) { // 左花括号前不换行。 var resultValue = Foo * mulNumber; // 局部变量使用 camelCase。 NumTimesCalled++; Foo += _bar; if (!NoCounting) { // 一元运算符后不加空格, // 'if' 后加空格。 if (resultValue < 0) { // 即使可选也使用花括号, // 比较运算符两侧加空格。 _results.NumNegativeResults++; } else if (resultValue > 0) { // 花括号和 else 之间不换行。 _results.NumPositiveResults++; } } return resultValue; } public void ExpressionBodies() { // 对于简单的 Lambda 表达式,尽量放在一行,不需要括号或花括号。 Func<int, int> increment = x => x + 1; // 右花括号与包含左花括号的行的第一个字符对齐。 Func<int, int, long> difference1 = (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }; // 如果在续行换行后定义,则整个函数体缩进。 Func<int, int, long> difference2 = (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }; // 内联 Lambda 参数也遵循这些规则。如果参数组包含 Lambda 表达式, // 建议在参数组前加一个换行。 CallWithDelegate( (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }); } void DoNothing() {} // 空代码块可以简写。 // 如果可能,通过将新行与第一个参数对齐来换行。 void AVeryLongFunctionNameThatCausesLineWrappingProblems(int longArgumentName, int p1, int p2) {} // 如果与第一个参数对齐不可行或难以阅读, // 则将所有参数换行到新行并缩进 4 个空格。 void AnotherLongFunctionNameThatCausesLineWrappingProblems( int longArgumentName, int longArgumentName2, int longArgumentName3) {} void CallingLongFunctionName() { int veryLongArgumentName = 1234; int shortArg = 1; // 如果可能,通过将新行与第一个参数对齐来换行。 AnotherLongFunctionNameThatCausesLineWrappingProblems(shortArg, shortArg, veryLongArgumentName); // 如果与第一个参数对齐不可行或难以阅读, // 则将所有参数换行到新行并缩进 4 个空格。 AnotherLongFunctionNameThatCausesLineWrappingProblems( veryLongArgumentName, veryLongArgumentName, veryLongArgumentName); } } }
Last updated on