对于C++文件(*.CPP和*.h),我们使用CLAN格式(版本3.6 +)来确保代码样式。在更改任何cpp或h文件之后,在合并之前,必须运行src/native/format-code.sh。此脚本将确保所有本机代码文件都遵循编码样式准则。
对于非代码文件(XML等),我们当前的最佳指导是一致性。编辑文件时,保持新代码和更改与文件中的样式一致。对于新文件,它应该符合该组件的样式。如果有一个全新的组件,任何被合理广泛接受的组件都可以。
我们遵循的一般规则是“使用Visual Studio默认值”。
1. 我们使用Allman样式的大括号,其中每个大括号都从新的行开始。单行语句块可以不带大括号,但块必须在自己的行上正确缩进,并且不能嵌套在使用大括号的其他语句块中(示例请参见问题381)。一个例外是,通过在同一缩进级别的下一行开始,允许using语句嵌套在另一个using语句中,即使嵌套的using包含受控块。
2. 我们使用四个空格而不是制表符。
3. 我们将_camelcase用于内部和私有字段,并尽可能使用readonly。为内部和私有实例字段加前缀_,静态字段加前缀s_,线程静态字段加前缀t_。当用于静态字段时,readonly应位于static之后(例如static readonly而不是readonly static)。公共字段应谨慎使用,使用时应使用不带前缀的PascalCasing。
4. 我们避免使用 this. 。除非绝对必要。
5. 我们总是指定可见性,即使它是默认值(例如private string _foo而不是string _foo)。可见性应该是第一个修饰符(例如public abstract 而不是abstract public)。
6. 命名空间导入应在文件的顶部、命名空间声明之外指定,并且应按字母顺序排序,System.*命名空间除外,它将放在所有其他命名空间的顶部。
7. 任何时候都避免使用多个空行。例如,一个类型的成员之间不能有两个空行。
8. 避免虚假的空格。例如,避免if(somevar==0)…,其中点标记是虚假的空格。如果使用Visual Studio辅助检测,请考虑启用“查看空白(Ctrl+E, S)”。
9. 如果某个文件的样式与这些准则不符(例如,私有成员命名为 m_member 而不是 _member),则该文件中的现有样式优先。
10. 我们只在变量类型十分明显时使用 var(例如 var stream = new FileStream(...) 而不是 var stream = OpenStandardInput()).)。
11. 对于类型引用(例如 int、string、float而不是Int32、String、Single等)和方法调用(例如 int.Parse(...) 而不是 Int32.Parse(...)),我们使用语言关键字而不是bcl类型。示例见第391期。
12. 我们使用PascalCasing来命名所有的常量、局部变量和字段。唯一的例外是interop代码,其中常量值应与通过interop调用的代码的名称和值完全匹配。
13. 我们尽可能使用 nameof(...),而不是 "..." 的名称。
14. 字段应在代码顶部,并声明类型。
15. 在源代码中包含非ASCII字符时,请使用Unicode转义序列(\uxxxx)而不是文字字符。文字非ASCII字符偶尔会被工具或编辑器弄乱。
16. 当为 goto 语句使用标签时,将标签缩进一个小于当前缩进的值。
我们在corefx存储库的根目录下提供了一个Visual Studio vssettings文件(corefx.vssettings),使C自动格式化符合上述准则。请注意,vssettings不包括规则7和8,因为这些规则当前不受vs格式支持。
此外,对于非Visual Studio编辑器中的自动格式化,还在corefx存储库的根目录下提供了editorconfig文件(.editorconfig)。
我们还使用.NET代码格式化工具来确保代码库在一段时间内保持一致的样式,该工具会自动修复代码库以符合上面概述的准则。
Example File:
ObservableLinkedList`1.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using Microsoft.Win32;
namespace System.Collections.Generic
{
public partial class ObservableLinkedList<T> : INotifyCollectionChanged, INotifyPropertyChanged
{
private ObservableLinkedListNode<T> _head;
private int _count;
public ObservableLinkedList(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
foreach (T item in items)
{
AddLast(item);
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public int Count
{
get { return _count; }
}
public ObservableLinkedListNode AddLast(T value)
{
var newNode = new LinkedListNode<T>(this, value);
InsertNodeBefore(_head, node);
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler handler = CollectionChanged;
if (handler != null)
{
handler(this, e);
}
}
private void InsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
...
}
...
}
}
ObservableLinkedList`1.ObservableLinkedListNode.cs:
using System;
namespace System.Collections.Generics
{
partial class ObservableLinkedList<T>
{
public class ObservableLinkedListNode
{
private readonly ObservableLinkedList<T> _parent;
private readonly T _value;
internal ObservableLinkedListNode(ObservableLinkedList<T> parent, T value)
{
Debug.Assert(parent != null);
_parent = parent;
_value = value;
}
public T Value
{
get { return _value; }
}
}
...
}
}