corefxリポジトリのコーディング規約(日本語訳)

dotnet/corefxリポジトリ内の[C# Coding Style](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md)の日本語訳です。
コード部分および脚注は自分が書き加えたものです。

## C++ファイル(*.cpp, *.h)
- __clang-format (version 3.6+)__に準拠する。
  - マージ前にsrc/Native/format-code.shを実行して、コードの自動整形をすること。

## コードファイル以外(*.xmlなど)
- フォーマットの一貫性を優先する。
  - 修正の場合は、既存のフォーマットに準拠する。
  - 新規作成の場合は、すでに作成された同種ファイルのフォーマットに準拠する。
  - 準拠する既存のファイルがない場合は、広く受け入れられたスタイルであればOK。

## C#ファイル(*.cs)

基本的にVisual Studioの初期設定に準ずる。

### ブラケット`{ }`
- [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style)に準拠する。
- 単一ステートメントのブラケットなし表記は許容するが、「インデントが適切である」「他のステートメントでネストされていない」場合のみ。(参考issue[#381](https://github.com/dotnet/corefx/issues/381))
- `using`ステートメントは例外で、他の`using`にネストされていてもブラケットを省略可能。

```csharp:Braces
// OK
public void Foo(int x, string y)
{
    // 単一ステートメントの場合は{ }がなくてもよい
    if (x < 0) throw new ArgumentException();

    // 2行に分ける場合も同様。ただしインデントは下げる
    if (y == null)
        throw new ArgumentNullException("Exception Message");

    // ネストされている場合は{ }必須
    if (x == 0)
    {
        if (y == "")
        {
            Console.WriteLine("String Empty");
        }
        Console.WriteLine("Int 0");
    }

    // 例外的に、usingはネストを深くしなくてよい
    using (var sr = new StreamReader())
    using (var sw = new StreamWriter())
    {
        // srとswのスコープはこのブロック内
    }
}

// NG(K&R style)
public void Bar(int x, string y) {

    // NGではないが、早期returnに{ }があるのは嫌われがち(issue#381)
    if (x < 0) { throw new ArgumentException(); }

    // NG(インデントを下げていない)
    if (y == null)
    throw new ArgumentNullException("Exception Message");

    // これはFooクラスと異なるコードパスとなる。
    // 以下のように解釈される。
    // =============================
    // if (x == 0)
    // {
    //     if (y == "")
    //     {
    //         Console.WriteLine("String Empty");
    //     }
    // }
    // Console.WriteLine("Int 0");
    // =============================
    // 上記のような勘違いを起こさないように、{ }を必須としている。
    if (x == 0)
        if (y == "")
            Console.WriteLine("String Empty");
        Console.WriteLine("Int 0");
}
```

### インデント
- 半角スペース4つ。(タブ文字は使わない)

### フィールド
- `internal`、`private`フィールドの場合は`_camelCase`のように命名する。
  - インスタンスフィールドは`_`をつける
  - `static`フィールドは`s_`をつける
  - スレッド内で`static`なフィールドには`t_`をつける
- 可能ならば`readonly`をつける
- `static`と`readonly`が重複する場合は、`static readonly`の語順にする。
- `public`フィールドは多用しない。 使用する場合は`PascalCase`のように命名する。

```csharp:Fields
using System.Threading;

public class Foo
{
    private int _count;
    private static readonly string s_foo;
    [ThreadStatic]
    private static string t_bar;
    public string PublicField;
}
```

### this参照
- 必要でない限りは、`this.`表記を使わない。 

```csharp:This
public class Foo
{
    // フィールドの命名規約に違反していますが、例ということでご容赦を……。
    private readonly int x;
    private readonly int y;

    public Foo(int x)
    {
        // thisを付けないと引数のxとみなされるため、必須
        this.x = x;
        // NG yでアクセス可能
        this.y = 20;
    }
}
```

### アクセシビリティ
- 省略可能な場合であっても、`private`などのアクセシビリティは明示する。
- アクセシビリティは先頭に書く。

```csharp:Visiblity
internal class Foo  // OK
{
    private string _text;  // OK
}

public abstract class Bar  // OK
{
}

class Foo  // NG(明示的にinternalを書く)
{
    string _text;  // NG(明示的にprivateを書く)
}

abstract public class Bar  // NG(public abstractの順)
{
}
```

### 名前空間
- 名前空間のインポート(`using`)は、ファイルの先頭かつ、`namespace`ブロックの外で行う。
- `System.*`以外の名前空間は、アルファベット順にソートする。
- `System.*`のインポート句は、先頭に持ってくる。

```csharp:Namespace
using System;
using System.Text;
using ACorp.Library;
using BCorp.Library;
using BCorp.Library.IO;

namespace ACorp.Product
{
}
```

### 空白行
- 空白行は1行まで。2行以上の空白行は認めない。

### スペース
- 行末のスペースなど、不要な空白は削除する。
    - IDEで明示的にスペースが見える設定にしておく。(Visual StudioではCtrl+E, S)

```csharp
// NG 見た目ではわかり辛いが、下の行末にスペースが3個ある
if (index == 0)   
{
}
```

### 既存コード
- 既存のコードファイルに、この規約に沿わないものがあった場合は、そのファイル内では既存の表記に従う。[^1]

### var
- 右辺から型が明らかな場合のみ使用する。

```csharp:Var
var stream = new FileStream();  // OK
var stream = OpenStandardInput();  // NG 戻り値の型を知らなければならない
```

### 組み込み型
- BCLの型名(`Int32`など)ではなく、キーワード(`int`)を使用する。(参考issue[#391](https://github.com/dotnet/corefx/issues/391))
 - `int.Parse`など、メソッドを呼び出す際も同様。

### 定数(`const`)
- ローカル定数とフィールド定数は、`PascalCase`で命名する。
  - ネイティブコード呼び出し等で定数名と値を合わせる必要がある場合には、この限りではない。

### nameof
- 可能な限り、`"Foo"`ではなく`nameof(Foo)`演算子を利用する。

```csharp:NameOf
public void Method(int index)
{
    // nameof演算子はコンパイル時に定数に変換される。
    // つまり、下記if文は同じ意味。
    // ただしnameof演算子を利用することで、IDE上での参照が追えるようになる。
    // (例えば引数indexをリネームした場合、前者は変更が追えるが後者は追えない)
    if (x < 0) throw new ArgumentException(nameof(index));
    if (x < 0) throw new ArgumentException("index");
}
```

### フィールド宣言
- フィールドは、型宣言の先頭に定義する。

### 非ASCII文字
- 非ASCII文字は、Unicodeエスケープリテラル(`\uXXXX`)を用いて表記する。
  - 非ASCII文字に非対応のエディタで問題が起きないようにするため。

### gotoラベル
- `goto`用のラベルを書く際には、インデントを1段階上げる。

```csharp
public void Method(int x)
{
    if (x < 0) goto Negative;
    DoSomething(x);
Negative:  // インデントを1段階上げる
    DoFinally();
}
```

## ツール類

### [EditorConfig](https://editorconfig.org "EditorConfig homepage")
- corefxリポジトリのルートにある[.editorconfigファイル](https://github.com/dotnet/corefx/blob/master/.editorconfig)で、上記規約をルール化している。
  - EditorConfigに対応しているエディタならば、上記の規約に従うよう自動整形される。[^2]

### [.NET Codeformatter Tool](https://github.com/dotnet/codeformatter)
- 実行時に、自動で上記の規約に沿うようファイルを整形するツール。

--------
## メモ
- `.editorconfig`の作成は、Visual Studio 2017以降で(.NET拡張部分も含め)グラフィカルに行える。
  - https://docs.microsoft.com/ja-jp/visualstudio/ide/code-styles-and-code-cleanup
- [.NET Codeformatter Tool](https://github.com/dotnet/codeformatter)はcorefx専用感が強いので、自プロジェクトで使う場合は[dotnet-format](https://github.com/dotnet/format/)を利用する 
 - `.editorconfig`に基づいてコードを整形してくれるツール

[^1]: 例えばシリアライズ可能なクラスの場合、`private`なフィールドであっても、名称の変更は破壊的変更になり得る。こうした「何らかの理由があって変更できない」コードが変更されてしまうのを防ぐためのルールだと思われる
[^2]: .NET拡張部分(フィールドの宣言など)は、Visual Studioのみの対応？