MSDN語パーフェクト文法マスター

## MSDN語とは

[こんなやつ](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.button?view=netframework-4.7.2)。
いわゆる MSDN (と呼ばれていた) における日本語の言い回しのこと。

![msdnlang-1.png](https://qiita-image-store.s3.amazonaws.com/0/339066/83f17a45-a8a1-b4a9-cfe1-af5f9bd360bb.png)

## マスターすると何が嬉しい？

C# でドキュメント コメントを書く際に、標準ライブラリっぽくなります。
コメントのスタイルまで統一できるなんて、さすが C# は違う。

## 注意事項

2010 年代前半にまとめた文章を発掘して、そのままリリースしています。
すでに内容が古いかもしれません！

## MSDN語

### 文体

文体は「です・ます」調で記述します。

```diff
-/// これは悪いコメントだ。
+/// これは良いコメントです。
```

`param` タグや `returns` タグの最初の文は名詞句で記述します。

```diff
-/// <param name="value">悪い値です。</param>
+/// <param name="value">良い値。</param>
```

句読点は「、」および「。」を使用します。

```diff
-/// これは, 悪いコメントです.
+/// これは、良いコメントです。
```

あらゆる文章の最後には「。」を記述します。

```diff
-/// これは悪いコメントです
+/// これは良いコメントです。
```

括弧は半角 `(` `)` を使用します。

```diff
-/// これは （悪い） コメントです。
+/// これは (良い) コメントです。
```

アルファベットや数字は半角文字を使用します。

```diff
-/// これは １ 番悪いコメントです。
+/// これは 1 番良いコメントです。
```

### 空白

全角文字と半角文字の境界には半角スペース ` ` を挿入します。

```diff
-/// <param name="source">これは悪いC#のコメント。</param>
+/// <param name="source">これは良い C# のコメント。</param>
```

句読点の前後に半角文字が続く場合は半角スペース ` ` を挿入しません。

```diff
-/// <param name="source">これは、 C# の悪いコメント。</param>
+/// <param name="source">これは、C# の良いコメント。</param>
```

括弧の直中に全角文字が続く場合は半角スペース ` ` を挿入しません。

```diff
-/// <param name="source">悪いコメント ( テスト )。</param>
+/// <param name="source">良いコメント (テスト)。</param>
```

タグの前後に全角文字が続く場合は半角スペース ` ` を挿入しません。

```diff
-/// <param name="source"> 悪いコメント。 </param>
+/// <param name="source">良いコメント。</param>
```

### 語句

(迷った時に) 文の最後は `表します。`、`表現します。`、`識別します。`、`定義します。`、`提供します。`、`公開します。` などで終わります。

コンストラクタの `summary` セクションは `{型名} クラスの新しいインスタンスを初期化します。` とします。
コンストラクタがパラメータを持つ場合や、コンストラクタがオーバーロードされている場合は `{型名} クラスの新しいインスタンスを、〜初期化します。` とします。

```cs
public sealed class Foo
{
    /// <summary>
    /// <see cref="Foo"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    public Foo() { ... }

    /// <summary>
    /// <see cref="Foo"/> クラスの新しいインスタンスを、指定した整数値で初期化します。
    /// </summary>
    public Foo(int n) { ... }
}
```

静的コンストラクタの `summary` セクションは `{型名} クラスを初期化します。` とします。

```cs
public static class Foo
{
    /// <summary>
    /// <see cref="Foo"/> クラスを初期化します。
    /// </summary>
    static Foo() { ... }
}
```

イベントの `summary` セクションは `～に発生します。` や `～ときに発生します。` とします。

```cs
/// <summary>
/// プロパティ値が変更されたときに発生します。
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
```

(迷った時に) イベント ハンドラ メソッドの `param` セクションは `イベント ソース。` および `イベント データ。` とします。

```cs
/// <summary>
/// ...
/// </summary>
/// <param name="sender">イベント ソース。</param>
/// <param name="e">イベント データ。</param>
private void button_Click(object sender, EventArgs e);
```

プロパティの `summary` セクションは `～を取得または設定します。` とします。

```cs
/// <summary>
/// ビューからの応答を取得または設定します。
/// </summary>
/// <value>ビューからの応答。</value>
object Response { get; set; }
```

読み取り専用プロパティの `summary` セクションは `～を取得します。` とします。

```cs
/// <summary>
/// このインタラクション メッセージを一意に識別できるグローバル一意識別子を取得します。
/// </summary>
/// <value>このインタラクション メッセージを一意に識別できるグローバル一意識別子。</value>
Guid Id { get; }
```

`bool` を返すプロパティの `summary` セクションには `～かどうかを示す値` を含めます。

```cs
/// <summary>
/// このオブジェクトが有効かどうかを示す値を取得します。
/// </summary>
/// <value>このオブジェクトが有効な場合は <c>true</c>。それ以外の場合は <c>false</c>。</value>
bool IsEnabled { get; }
```

プロパティの既定値が重要な場合は `summary` セクションに `既定値は、～です。` と記述します。

```cs
/// <summary>
/// このビュー モデルで使用できるインタラクション メッセンジャーを取得または設定します。
/// </summary>
/// <value>
/// このビュー モデルで使用できるインタラクション メッセンジャー。
/// 既定値は、<see cref="InteractionMessenger.Default"/> です。
/// </value>
IInteractionMessenger Messenger { get; set; }
```

`bool` を返すメソッドの `summary` セクションは `～かどうかを判断します。` とします。

```cs
/// <summary>
/// 現在の状態でこのコマンドを実行できるかどうかを判断します。
/// </summary>
/// <param name="parameter">コマンドで使用されたデータ。</param>
/// <value>このコマンドを実行できる場合は <c>true</c>。それ以外の場合は <c>false</c>。</value>
bool CanExecute(T parameter);
```

`bool` を返すプロパティまたはメソッドの `value` セクションは `～の場合は <c>true</c>。それ以外の場合は <c>false</c>。` とします。

```cs
/// <summary>
/// このオブジェクトが有効かどうかを示す値を取得します。
/// </summary>
/// <value>このオブジェクトが有効な場合は <c>true</c>。それ以外の場合は <c>false</c>。</value>
bool IsEnabled { get; }
```

イベントを発生させるメソッドの `summary` セクションは `{イベント} イベントを発生させます。` とします。

```cs
/// <summary>
/// <see cref="ICommand.CanExecuteChanged"/> イベントを発生させます。
/// </summary>
void RaiseCanExecuteChanged();
```

メソッドが派生クラスによるイベントの購読を目的としている場合は `summary` セクションを `{イベント} イベントが発生したときに呼びだされます。` とします。

```cs
/// <summary>
/// <see cref="Attached"/> イベントが発生したときに呼びだされます。
/// </summary>
protected virtual void OnAttached() { ... }
```

`ArgumentNullException` のドキュメントは `<paramref name="{パラメータ}"/> が <c>null</c> です。` とします。

```cs
/// <summary>
/// <see cref="AnonymousDisposable"/> クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="dispose"><see cref="IDisposable.Dispose"/> から一度だけ呼びだされるデリゲート。</param>
/// <exception cref="ArgumentNullException"><paramref name="dispose"/> が <c>null</c> です。</exception>
public AnonymousDisposable([NotNull] Action dispose)
{
    _dispose = dispose ?? throw new ArgumentNullException(nameof(dispose));
}
```

`ObjectDisposedException` のドキュメントは `オブジェクトは解放済みです。` とします。

```cs
/// <exception cref="ObjectDisposedException">オブジェクトは解放済みです。</exception>
```

宣言が `abstract` の場合は `summary` セクションの先頭に `派生クラスで実装されると、` と記述します。

```cs
/// <summary>
/// 派生クラスで実装されると、このトリガー アクション固有のアクションを実行します。
/// </summary>
/// <param name="parameter">パラメータ。</param>
protected abstract void Invoke(object parameter);
```

型パラメータが共変または反変の場合は決められた内容を記述します。

```cs
/// <summary>
/// </summary>
/// <typeparam name="TValue">
/// ...
/// このパラメータが反変の型パラメータです。
/// つまり、その指定した型を使用するか、それよりも弱い任意の派生型を使用することができます。
/// 共変性と反変性の詳細については、「ジェネリックの共変性と反変性」を参照してください。
/// </typeparam>
/// <typeparam name="TResult">
/// ...
/// このパラメータが共変の型パラメータです。
/// つまり、その指定した型を使用するか、それよりも強い任意の派生型を使用することができます。
/// 共変性と反変性の詳細については、「ジェネリックの共変性と反変性」を参照してください。
/// </typeparam>
public interface IObserver<in TValue, out TResult> { ... }
```

メソッドをシールし派生クラスに別のカスタマイズ ポイントを提供する場合は決められた内容を記述します。

```cs
/// <summary>
/// アクションを呼び出します。
/// </summary>
/// <param name="parameter">アクションへのパラメータ。</param>
/// <remarks>
/// このメソッドはシールされています。
/// このロジックを特別にオーバーライドするには、派生クラスで
/// <see cref="InvokeCore"/> をオーバーライドする必要があります。
/// </remarks>
protected override sealed void Invoke(object parameter)
{
    :
    InvokeCore(message);
}

/// <summary>
/// 派生クラスでオーバーライドされると、インタラクション メッセージを処理します。
/// </summary>
/// <param name="message">受信したインタラクション メッセージ。</param>
protected virtual void InvokeCore(object message) { ... }
```

依存関係プロパティのドキュメントには決められた内容を記述します。

```cs
#region IsFloating 依存関係プロパティ
/// <summary>
/// <see cref="IsFloating"/> 依存関係プロパティを識別します。
/// </summary>
[NotNull]
private static readonly DependencyPropertyKey IsFloatingPropertyKey
    = DependencyProperty.RegisterReadOnly(
        nameof(IsFloating),
        typeof(bool),
        typeof(FloatingLabel),
        new PropertyMetadata(false, IsFloatingChangedCallback));

/// <summary>
/// <see cref="IsFloating"/> 依存関係プロパティを識別します。
/// </summary>
[NotNull]
public static readonly DependencyProperty IsFloatingProperty = IsFloatingPropertyKey.DependencyProperty;

/// <summary>
/// フローティング ラベルがフロート表示されているかどうかを示す値を取得します。
/// これは依存関係プロパティです。
/// </summary>
/// <value>フローティング ラベルがフロート表示されている場合は <c>true</c>。それ以外の場合は <c>false</c>。</value>
public bool IsFloating
{
    get => (bool)GetValue(IsFloatingProperty);
    private set => SetValue(IsFloatingPropertyKey, value);
}

/// <summary>
/// <see cref="IsFloating"/> 依存関係プロパティが変更されたときに呼び出されます。
/// </summary>
/// <param name="d">イベント ソース。</param>
/// <param name="e">イベント データ。</param>
private static void IsFloatingChangedCallback([NotNull] DependencyObject d, DependencyPropertyChangedEventArgs e)
    => ((FloatingLabel)d).OnIsFloatingChanged((bool)e.OldValue, (bool)e.NewValue);

/// <summary>
/// <see cref="IsFloating"/> 依存関係プロパティが変更されたときに呼び出されます。
/// </summary>
/// <param name="oldIsFloating">変更される前の値。</param>
/// <param name="newIsFloating">変更された後の値。</param>
protected virtual void OnIsFloatingChanged(bool oldIsFloating, bool newIsFloating) { ... }
#endregion
```

パラメータが `out` パラメータの場合は最後に `このパラメータは初期化せずに渡されます。` と記述します。

```cs
/// <summary>
/// パケットを受信します。
/// このメソッドは、複数のスレッドから同時にアクセスすることができます。
/// </summary>
/// <param name="description">
/// 受信したパケットの概要。
/// このパラメータは初期化せずに渡されます。
/// </param>
/// <returns>パケットを受信しており、<paramref name="description"/> に値が格納された場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
public override bool TryReceive(out PacketDescription description) { ... }
```