diff --git a/CLAUDE.md b/CLAUDE.md index 13edaea..605ed70 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,8 +35,8 @@ [GUIDE_04_コーディング規則.txt](docs/01_GUIDE/GUIDE_04_コーディング規則.txt) -Python コードの書き方を定義する。PEP 8 準拠,snake_case / PascalCase / UPPER_SNAKE_CASE の使い分け, -型ヒント必須,`from ... import *` 禁止,マジックナンバー禁止など。 +C# コードの書き方を定義する。Microsoft コーディング規則準拠,PascalCase / camelCase / `_camelCase` の使い分け, +波括弧スタイル(同一行),`var` の使用方針,マジックナンバー禁止など。 --- @@ -44,5 +44,5 @@ [GUIDE_05_コードコメント規則.txt](docs/01_GUIDE/GUIDE_05_コードコメント規則.txt) -コメント・docstring の書き方を定義する。モジュール・クラス・公開関数には docstring 必須。 -コメントは日本語,句読点は「,」を使用,文末の「.」は付けない。Google スタイルの docstring を使用する。 +コメント・XML ドキュメントコメントの書き方を定義する。クラス・public / protected メンバーには `/// ` 必須。 +コメントは日本語,句読点は「,」を使用,文末の「.」は付けない。 diff --git "a/docs/01_GUIDE/GUIDE_04_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\345\211\207.txt" "b/docs/01_GUIDE/GUIDE_04_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\345\211\207.txt" index 1bce5cf..070f242 100644 --- "a/docs/01_GUIDE/GUIDE_04_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\345\211\207.txt" +++ "b/docs/01_GUIDE/GUIDE_04_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\345\211\207.txt" @@ -1,11 +1,12 @@ ======================================================================== -Python コーディング規則 (Python Coding Style Guide) +C# コーディング規則 (C# Coding Style Guide) ======================================================================== 1. 基本方針 (Basic Policy) ------------------------------------------------------------------------ -PEP 8 を基本とし,チーム内での一貫性を最優先とする. -本規則に明記されていない事項は PEP 8 に従う. +Microsoft の C# コーディング規則および .NET ランタイム コーディングガイド +ラインを基本とし,チーム内での一貫性を最優先とする. +本規則に明記されていない事項は Microsoft 公式ガイドラインに従う. ※ 書式・記述スタイルの基準は `GUIDE_01_ドキュメント作成ガイド.txt` を参照する. @@ -17,29 +18,43 @@ ・継続行は,開き括弧に揃えるか,ハンギングインデント(スペース4つ追加)とする. ・例: - # 開き括弧に揃える - result = some_function(arg_one, arg_two, - arg_three, arg_four) + // 開き括弧に揃える + var result = SomeMethod(argOne, argTwo, + argThree, argFour); - # ハンギングインデント - result = some_function( - arg_one, arg_two, - arg_three, arg_four, - ) + // ハンギングインデント + var result = SomeMethod( + argOne, argTwo, + argThree, argFour); -2-2. 1行の最大文字数 - ・79文字を上限とする(PEP 8 準拠). - ・文字列やコメントが長くなる場合は,括弧による暗黙の行継続を優先する. - ・バックスラッシュ `\` による行継続は極力避ける. +2-2. 波括弧 (Braces) + ・開き波括弧「{」は,宣言と同じ行に記述する(K&R スタイル). + ・例: -2-3. 空行 - ・トップレベルの関数・クラス定義の間: 2行空ける. - ・クラス内のメソッド定義の間: 1行空ける. - ・関数内の論理的なまとまりの区切り: 1行空ける(使いすぎに注意). + namespace TIASshot { + internal class MotorController { + public void Start() { + if (IsRunning) { + ... + } + } + } + } -2-4. 文字コード - ・UTF-8 を使用する. - ・エンコーディング宣言(`# -*- coding: utf-8 -*-`)は Python 3 では不要. + ・単文の `if` / `for` 等でも,必ず波括弧を付ける. + - NG: `if (isActive) return;` + - OK: `if (isActive) { return; }` + +2-3. 1行の最大文字数 + ・120文字を目安とする.超える場合は適切な位置で改行する. + +2-4. 空行 + ・クラス定義の間: 2行空ける. + ・メソッド定義の間: 1行空ける. + ・メソッド内の論理的なまとまりの区切り: 1行空ける(使いすぎに注意). + +2-5. 文字コード + ・UTF-8(BOM なし)を使用する. 3. 命名規則 (Naming Conventions) @@ -47,170 +62,187 @@ 3-1. 一覧 - ■ 変数・関数・メソッド・引数 - ・スタイル: snake_case - ・例: `motor_speed`,`calc_distance`,`handle_input` - - ■ 定数 - ・スタイル: UPPER_SNAKE_CASE - ・例: `MAX_SPEED`,`DEFAULT_PORT`,`PIN_MOTOR_LEFT` - - ■ クラス + ■ クラス・構造体・列挙型・デリゲート ・スタイル: PascalCase - ・例: `MotorController`,`SensorReader`,`UltrasonicSensor` + ・例: `CameraBase`,`MotorController`,`DeviceStatus` - ■ モジュール(ファイル名) - ・スタイル: snake_case - ・例: `motor_controller.py`,`sensor_reader.py` + ■ インターフェース + ・スタイル: 「I」プレフィックス + PascalCase + ・例: `ICamera`,`IDeviceControl` - ■ パッケージ(ディレクトリ名) - ・スタイル: 全て小文字,アンダースコアなし(短い名前を推奨) - ・例: `drivers`,`utils`,`config` + ■ メソッド・イベント・プロパティ + ・スタイル: PascalCase + ・例: `Connect()`,`GetDataName()`,`IsCalibrating` - ■ プライベート - ・先頭にアンダースコア1つを付与する. - ・例: `_internal_value`,`_calc_raw_data` + ■ ローカル変数・引数 + ・スタイル: camelCase + ・例: `cameraList`,`saveFolder`,`numImages` + + ■ プライベートフィールド + ・スタイル: アンダースコア + camelCase + ・例: `_camera`,`_isLightOn`,`_calibrating` + + ■ 定数・static readonly フィールド(公開) + ・スタイル: PascalCase + ・例: `MaxSpeed`,`DefaultPort`,`AppName` + ※ 既存コードの `UPPER_SNAKE_CASE`(例: `APP_NAME`)は互換性のため許容するが, + 新規定義は `PascalCase` に統一する. + + ■ 非同期メソッド + ・スタイル: PascalCase + `Async` サフィックス + ・例: `ConnectAsync()`,`SaveImagesAsync()`,`LoadConfigAsync()` + + ■ 列挙型メンバー + ・スタイル: PascalCase + ・例: `DeviceStatus.Connected`,`CaptureMode.Single` 3-2. 命名の原則 ・意味のある名前を付け,略語は最小限にする. - - NG: `d`,`tmp`,`val`,`calc`(単体で使用) - - OK: `distance`,`temperature`,`motor_value` + - NG: `d`,`tmp`,`val` + - OK: `distance`,`temperature`,`motorValue` ・ループカウンタ等,スコープが極めて狭い場合のみ `i`,`j`,`x`,`y` を許容する. - ・bool 型の変数は `is_`,`has_`,`can_` 等の接頭辞を付ける. - - 例: `is_connected`,`has_obstacle`,`can_move` + ・bool 型のプロパティ・変数は `Is`,`Has`,`Can` 等の接頭辞を付ける. + - 例: `IsConnected`,`HasObstacle`,`CanCapture` -4. import の規則 (Import Rules) +4. using ディレクティブの規則 (Using Directives) ------------------------------------------------------------------------ 4-1. 順序 以下の順序で記述し,グループ間に1行空ける. - 1. 標準ライブラリ(`os`,`sys`,`time` 等) - 2. サードパーティライブラリ(`RPi.GPIO`,`numpy` 等) - 3. プロジェクト内モジュール + 1. System 名前空間(`System`,`System.Collections.Generic` 等) + 2. サードパーティライブラリ(`OpenCvSharp`,`TIS.Imaging` 等) + 3. プロジェクト内名前空間 ・例: - import os - import sys - import time + using System; + using System.Collections.Generic; + using System.IO; - import RPi.GPIO as GPIO + using OpenCvSharp; - from drivers.motor import MotorController - from sensors.ultrasonic import UltrasonicSensor + using TIASshot.Camera; 4-2. スタイル - ・1行に1モジュールを記述する. - - NG: `import os, sys` - - OK: `import os` と `import sys` を別行に記述 - ・`from ... import *` は禁止する(名前空間の汚染を防ぐ). - ・`from ... import` で複数の名前を取り込む場合は括弧でまとめる. - - from sensors.ultrasonic import ( - UltrasonicSensor, - TRIGGER_PIN, - ECHO_PIN, - ) + ・不要な `using` は削除する. + ・`using static` は,同一クラスのメンバーを多用する場合のみ許容する. -5. 型ヒント (Type Hints) +5. 型の使用規則 (Type Usage) ------------------------------------------------------------------------ -5-1. 方針 - ・関数の引数と返り値には型ヒントを付与する. - ・ローカル変数への型ヒントは,型が自明でない場合のみ付与する. +5-1. var の使用 + ・右辺に型名が明示されている場合は `var` を使用する. + - OK: `var list = new List();` + - OK: `var controller = new MotorController();` + ・右辺から型が読み取れない場合は明示的な型を使用する. + - NG: `var result = GetResult();`(戻り値の型が不明確) + - OK: `XmlNode result = doc.SelectSingleNode("//Config");` -5-2. 書式 - ・Python 3.10 以降の記法(`X | None`,`list[int]`)を使用する. - ・例: - - def calc_distance(speed: float, duration: float) -> float: - return speed * duration - - def find_obstacle(sensors: list[UltrasonicSensor]) -> int | None: - ... +5-2. null 許容参照型 (Nullable Reference Types) + ・`null` との比較は `is null` / `is not null` を使用する. + - NG: `if (value == null)` + - OK: `if (value is null)` + ・null 合体演算子(`??`,`??=`)や null 条件演算子(`?.`,`?[]`)を積極的に活用する. 6. コーディングルール (Coding Rules) ------------------------------------------------------------------------ -6-1. 比較 - ・`None` との比較は `is` / `is not` を使用する. - - NG: `if value == None:` - - OK: `if value is None:` - ・bool 値との比較は暗黙的に行う. - - NG: `if is_active == True:` - - OK: `if is_active:` +6-1. 文字列 + ・文字列の組み立てには文字列補間(`$"..."`)を使用する. + - NG: `"Speed: " + speed.ToString()` + - OK: `$"Speed: {speed}"` + ・定数文字列は `const string` または `static readonly string` で定義する. -6-2. 文字列 - ・引用符はダブルクォート `"` で統一する. - ・文字列の組み立てには f-string を使用する. - - NG: `"Speed: " + str(speed)` - - OK: `f"Speed: {speed}"` +6-2. 例外処理 + ・裸の `catch (Exception)` は極力避け,具体的な例外クラスを指定する. + - NG: `catch (Exception) { }` + - OK: `catch (ArgumentException ex) { ... }` + ・例外を握りつぶす場合(空の catch 節)は,必ず理由をコメントで明記する. -6-3. 例外処理 - ・裸の `except:` は禁止する.必ず例外クラスを指定する. - - NG: `except:` - - OK: `except ValueError:` - ・`except Exception` も極力避け,具体的な例外を捕捉する. - -6-4. with 文 - ・ファイル操作や GPIO のクリーンアップなど,リソース管理には `with` 文を使用する. +6-3. リソース管理 + ・`IDisposable` を実装するオブジェクトは `using` 文で管理する. ・例: - with open("config.json", "r") as f: - config = json.load(f) + using (var reader = new StreamReader(csvFile)) { + while (!reader.EndOfStream) { + ... + } + } -6-5. マジックナンバーの禁止 - ・意味のある数値は定数として定義する. - - NG: `time.sleep(0.5)` +6-4. マジックナンバーの禁止 + ・意味のある数値や文字列は定数として定義する. + - NG: `Thread.Sleep(500);` - OK: - SENSOR_INTERVAL_SEC = 0.5 - time.sleep(SENSOR_INTERVAL_SEC) + const int SensorIntervalMs = 500; + Thread.Sleep(SensorIntervalMs); + +6-5. readonly の使用 + ・コンストラクタ以降に値が変わらないフィールドは `readonly` を付ける. + - NG: `private float _updateRate;`(コンストラクタで1度だけ代入する場合) + - OK: `private readonly float _updateRate;` + ・`static readonly` はクラス定数(`const` にできない参照型など)に使用する. + +6-6. プロパティ vs 公開フィールド + ・`public` フィールドは原則定義しない.外部に公開する値はプロパティを使用する. + - NG: `public string DeviceName;` + - OK: `public string DeviceName { get; protected set; }` + ・外部から読み取りのみ許可する場合は `get` のみ,または `{ get; private set; }` とする. + +6-7. アクセス修飾子 + ・アクセス修飾子は必ず明示する(省略しない). + - NG: `class Config { ... }` + - OK: `internal static class Config { ... }` + +6-8. UI スレッド + ・ワーカースレッドから UI 操作を行う場合は `InvokeRequired` を確認してから + `Invoke` / `BeginInvoke` を使用する. + ・例: + + public void ShowMessage(string msg) { + if (InvokeRequired) { + Invoke((MethodInvoker)delegate { ShowMessage(msg); }); + return; + } + txtMessage.Text = msg; + } 7. ファイル構成 (File Structure) ------------------------------------------------------------------------ -1つの Python ファイル内は,以下の順序で記述する. +1つの C# ファイル内は,以下の順序で記述する. - 1. ファイルドキュメント(docstring) - 2. import 文 - 3. 定数定義 - 4. クラス定義 / 関数定義 - 5. `if __name__ == "__main__":` ブロック(必要な場合のみ) + 1. using ディレクティブ + 2. namespace 宣言 + 3. クラス定義(フィールド → プロパティ → コンストラクタ → メソッド) ・例: - """ - motor_controller - モーターの制御を担当するモジュール - """ + using System; + using System.IO; - import time + namespace TIASshot { + internal class MotorController { + // フィールド + private bool _isRunning = false; - import RPi.GPIO as GPIO + // プロパティ + public bool IsRunning => _isRunning; - from config.pins import PIN_MOTOR_LEFT, PIN_MOTOR_RIGHT + // コンストラクタ + public MotorController() { + ... + } - MAX_SPEED = 100 - DEFAULT_SPEED = 50 - - - class MotorController: - """左右のモーターを制御するクラス""" - - def __init__(self, left_pin: int, right_pin: int) -> None: - ... - - def forward(self, speed: int = DEFAULT_SPEED) -> None: - ... - - - if __name__ == "__main__": - controller = MotorController(PIN_MOTOR_LEFT, PIN_MOTOR_RIGHT) - controller.forward() + // メソッド + public void Start() { + ... + } + } + } 8. ツール設定 (Tooling) @@ -218,13 +250,17 @@ コードの品質を自動で維持するため,以下のツールの導入を推奨する. ■ フォーマッター -・black: コードの自動整形に使用する. - - 1行の最大文字数は 79 に設定する. +・`.editorconfig` に本規則の設定を記述し,チームで共有する(IDE 共通). +・Visual Studio: Ctrl+K, Ctrl+D でフォーマットを実行する. +・VSCode: C# Dev Kit 拡張機能を導入し,Shift+Alt+F でフォーマットを実行する. + - 保存時自動フォーマット(`editor.formatOnSave: true`)の設定を推奨する. ■ リンター -・flake8 または ruff: スタイル違反や潜在的なバグを検出する. +・Roslyn Analyzers を使用する(Visual Studio・VSCode 共通で動作する). + - `Microsoft.CodeAnalysis.NetAnalyzers` パッケージの導入を推奨する. -■ 型チェッカー -・mypy: 型ヒントの整合性を静的に検証する. +■ 型チェック +・Visual Studio・VSCode いずれの場合も,ビルドエラー・警告を全て解消してからコミットする. +・dotnet CLI: `dotnet build` でエラーがないことを確認する. ※ ツールの具体的な設定や導入手順は `ENV_` カテゴリのドキュメントに記載する. diff --git "a/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\211\343\202\263\343\203\241\343\203\263\343\203\210\350\246\217\345\211\207.txt" "b/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\211\343\202\263\343\203\241\343\203\263\343\203\210\350\246\217\345\211\207.txt" index 671a5d3..a066da6 100644 --- "a/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\211\343\202\263\343\203\241\343\203\263\343\203\210\350\246\217\345\211\207.txt" +++ "b/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\211\343\202\263\343\203\241\343\203\263\343\203\210\350\246\217\345\211\207.txt" @@ -5,8 +5,8 @@ 1. 基本方針 (Basic Policy) ------------------------------------------------------------------------ -コードの可読性と保守性を高めるため,ファイル・クラス・関数・定数それぞれに対して -適切な粒度でコメントを記述する. +コードの可読性と保守性を高めるため,ファイル・クラス・メソッド・定数それ +ぞれに対して適切な粒度でコメントを記述する. ※ コードの書き方自体の規則は `GUIDE_04_コーディング規則.txt` を参照する. ・言語: 日本語で記述する. @@ -20,135 +20,131 @@ 2. コメントの種類と用途 (Comment Types) ------------------------------------------------------------------------ -2-1. ファイルドキュメント (Module Docstring) - ・ファイルの先頭に必ず記述する. - ・トリプルダブルクォート(`""" """`)を使用する. +2-1. XML ドキュメントコメント (XML Doc Comment) + ・全ての public / protected メソッド・プロパティ・クラスに必ず記述する. + ・トリプルスラッシュ(`///`)を使用する. + + ■ クラス・構造体 ・書式: - """ - [ファイル名(拡張子なし)] - [ファイルの主な責務を1行で説明] - [補足情報があれば続けて記述] - """ + /// + /// [そのクラスが何を表すかを端的に説明] + /// + internal class ClassName { ... } ・例: - """ - motor_controller - モーターの制御を担当するモジュール - GPIO を介して左右のモーターの速度・方向を制御する - """ + /// + /// カメラの基底クラス + /// + internal abstract class CameraBase { ... } -2-2. クラスドキュメント (Class Docstring) - ・全てのクラスに記述する. - ・クラス定義の直後にトリプルダブルクォートで記述する. + ■ メソッド(引数・戻り値あり) ・書式: - class ClassName: - """[そのクラスが何を表すかを端的に説明]""" - - ・複数行が必要な場合: - - class ClassName: - """ - [そのクラスが何を表すかを端的に説明] - [補足情報] - """ + /// + /// [その処理を端的に説明] + /// + /// [説明] + /// [戻り値の説明] + public ReturnType MethodName(Type argName) { ... } ・例: - class MotorController: - """左右のモーターを GPIO 経由で制御するクラス""" + /// + /// CSV ファイルから Mat を読み込む + /// + /// 読み込む CSV ファイルパス + /// 読み込んだ Mat,失敗時は null + private Mat LoadMatFromCsv(string csvFile) { ... } -2-3. 関数・メソッドドキュメント (Function Docstring) - ・公開関数・メソッドには必ず記述する. - ・Google スタイルの docstring を使用する. + ■ メソッド(引数・戻り値なし,または自明) + ・1行で記述してよい. + + /// + /// 全モーターを停止する + /// + public void Stop() { ... } + + ■ 例外をスローする可能性がある場合 + ・`` タグを追加する. + + /// + /// 設定ファイルから float 値を取得する + /// + /// 設定キー(例: "Calib/UpdateRate") + /// float 値 + /// + /// 指定されたキーが存在しない場合 + /// + public static float GetFloat(string param) { ... } + + ■ 廃止予定のメンバー + ・`` タグで代替メンバーを案内し,`[Obsolete]` 属性を付ける. + + /// + /// 画像を保存する + /// + /// 非推奨: SaveImageAsync を使用すること + [Obsolete("SaveImageAsync を使用してください")] + public void SaveImage() { ... } + + ■ オーバーライドしたメンバー + ・基底クラスの doc comment を継承する場合は `` を使用する. + ・改めて説明を書く場合はオーバーライド先に通常の `` を記述する. + + /// + public override bool Connect() { ... } + + ■ 他メンバーへの参照 + ・説明文中で他のクラスやメンバーを参照する場合は `` を使用する. + + /// + /// から設定値を読み込む + /// + public void Load() { ... } + + /// + /// 接続に失敗した場合は を参照すること + /// + public bool Connect() { ... } + +2-2. フィールド・定数コメント (Field / Constant Comment) + ・公開される定数・フィールドにはインラインコメント(`//`)を直前行に記述する. ・書式: - def function_name(arg1: type, arg2: type) -> return_type: - """[その関数が何をするかを端的に説明] - - Args: - arg1: [説明] - arg2: [説明] - - Returns: - [返り値の説明] - """ - - ・引数・返り値がない,または自明な場合は1行で省略してよい. - - def stop(self) -> None: - """全モーターを停止する""" - - ・例外をスローする可能性がある場合は `Raises` セクションを付ける. - - def set_speed(self, speed: int) -> None: - """モーターの速度を設定する - - Args: - speed: 0〜100 の範囲の速度値 - - Raises: - ValueError: speed が 0〜100 の範囲外の場合 - """ - - ・廃止予定のものには非推奨であることを明記し,代替を示す. - - def old_method(self) -> None: - """非推奨: new_method を使用すること""" + // [その定数・フィールドが何を表すかを端的に説明] + public static string ConstantName = value; ・例: - def calc_distance(speed: float, duration: float) -> float: - """速度と時間から距離を計算する + // アプリケーション名 + public static string APP_NAME = "TIAS Shot"; - Args: - speed: 移動速度 (m/s) - duration: 経過時間 (s) + // 校正中フレームのカウンタ(0 より大きければ校正中) + protected int _calibrating = 0; - Returns: - 移動距離 (m) - """ - return speed * duration - -2-4. 定数ドキュメント (Constant Comment) - ・公開される定数にはインラインコメント(`#`)を直前行に記述する. +2-3. ブロックコメント (Block Comment) + ・メソッド内で処理のまとまりが変わる箇所に記述する. + ・`//` + 半角スペースを使用する. ・書式: - # [その定数が何を表すかを端的に説明] - CONSTANT_NAME = value - - ・例: - - # UI側と共有する最大速度の既定値 - MAX_SPEED = 100 - - # 超音波センサーの測定間隔 (秒) - SENSOR_INTERVAL_SEC = 0.5 - -2-5. ブロックコメント (Block Comment) - ・関数・メソッド内で,処理のまとまりが変わる箇所に記述する. - ・`#` + 半角スペースを使用する. - ・書式: - - # [このブロックの処理を端的に説明] + // [このブロックの処理を端的に説明] ...処理... ・例: - # 入力値を正規化する - normalized = raw_value / MAX_VALUE + // ARマーカー検出 + CvAruco.DetectMarkers(img, ARDict, out var corners, out var ids, ...); - # モーターに速度を反映する - GPIO.output(self._pin, normalized) + // チャートの固定判定 + var dist = (float)position.DistanceTo(_lastPosition); -2-6. タスクコメント (Task Comment) +2-4. タスクコメント (Task Comment) ・後で対応が必要な箇所に記述し,担当者と内容を明記する. - ・`#` + 半角スペースを使用し,以下のタグで種別を区別する. ・書式: - # [タグ]([担当者名]): [内容] + // [タグ]([担当者名]): [内容] ■ タグ定義: - TODO : 将来的に実装・対応が必要な箇所 @@ -157,9 +153,9 @@ ・例: - # TODO(yamada): タイムアウト処理を実装する - # FIXME(tanaka): 距離が負になるケースでクラッシュする - # HACK(suzuki): API仕様確定まで固定値で代替している + // TODO(yamada): タイムアウト処理を実装する + // FIXME(tanaka): 負の距離が入力された場合にクラッシュする + // HACK(suzuki): API 仕様確定まで固定値で代替している ・注意: - 「いつか直す」ではなく,必ずタスク管理ツールとセットで運用する @@ -169,29 +165,25 @@ 3. 記述しない場合の判断基準 (When to Omit) ------------------------------------------------------------------------ -・ファイル内部でのみ使用し,外部に公開されない関数・定数は省略してもよい -・コード自体が自明な場合(変数名で意図が十分伝わる場合)は省略してもよい -・ユニットテストファイルは,テストケース名で意図が伝わる場合は省略してもよい +・ファイル内部でのみ使用し,外部に公開されない private メンバーは省略してもよい +・コード自体が自明な場合(メンバー名で意図が十分伝わる場合)は省略してもよい +・自動生成コード(`*.Designer.cs` 等)は対象外とする 4. NG例 (Anti-patterns) ------------------------------------------------------------------------ ・句点を付ける - - NG: """ジョイスティックの入力を受け取る.""" - - OK: """ジョイスティックの入力を受け取る""" + - NG: /// 画像を保存する. + - OK: /// 画像を保存する ・「、」「。」を使う - - NG: # 入力開始時の基準座標をセットする。 - - OK: # 入力開始時の基準座標をセットする + - NG: // 撮影開始時の基準座標をセットする。 + - OK: // 撮影開始時の基準座標をセットする ・コードをコメントアウトして残す - - NG: # old_handler = lambda: ... - - OK: 不要なコードは削除する(Git履歴から復元できる) + - NG: //_lucam.StartStopPreview(); + - OK: 不要なコードは削除する(Git 履歴から復元できる) -・docstring を通常のコメントで書く - - NG: # motor_controller: モーターの制御を担当するモジュール - - OK: - """ - motor_controller - モーターの制御を担当するモジュール - """ +・XML doc comment を通常コメントで書く + - NG: // Connect: デバイスに接続する + - OK: /// デバイスに接続する