# Unity C#コーディング規約(テンプレート)
## はじめに
コーディング規則には、次の目的があります。
* コードの見た目が統一されるため、読みやすくなります。
* 経験に基づいて推測することで、迅速に理解することができます。
* コードのコピー、変更、保守が容易になります。
***
## 変数名の表記方法の種類について
### キャメルケース
* 単語の先頭を大文字にしてつなげる表記方法
### ローワーキャメルケース
* 最初の文字を小文字にしたキャメルケース
```c#
int shotSpawn = 0;
```
### アッパーキャメルケース(パスカルケース)
* 最初の文字を大文字にしたキャメルケース
```c#
int ShotSpawn = 0;
```
### スネークケース
* 単語と単語を「_」でつなげる表記方法
```c#
int shot_spawn = 0;
```
### コンスタントケース
* 全ての文字を大文字にしたスネークケース
```c#
int SHOT_SPAWN = 0;
```
***
## 命名規則について
### フィールド変数の定義について
* フィールド(メンバ)変数の定義はローワーキャメルケースで記述します。
* 定数の定義は「コンスタントケース」で記述します。
* static変数の定義は「ローワーキャメルケース」で記述します。
* bool型の変数名は頭に「is」をつける(例:isJump)
```C#
// 必要に応じてクラス群をnamespaceでまとめます
namespace Player
{
// クラス名はパスカルケースで命名します
public class ClassName : MonoBehaviour
{
// 他クラスから参照可能な定数
public const float MAX_SHOT_SPAWN = 4;
// クラス内でのみ使用する定数
private const int MAX_BULLET = 30;
// 他クラスから参照可能な静的変数
public static int testValue1;
// クラス内でのみ使用する静的変数
private static int testValue2;
// 他クラスから参照可能でインスペクターから値を設定できる変数
public int testValue3;
// 他クラスから参照可能だがインスペクターに表示されない変数
[System.NonSerialized] public int testValue4;
// クラス内でのみ使用する変数
private bool isValue5;
// クラス内でのみ使用し、インスペクターから値を設定できる変数
[SerializeField] private int testValue6;
}
}
```
### プロパティの定義について
* プロパティはパスカルケースで定義します
```c#
// 他クラスから参照のみ可能で、クラス内でのみ代入可能な変数
public string PlayerName1 { get; private set; }
// 上記と同じ意味だがインスペクターに表示したい場合
[SerializeField] private string playerName2;
public string PlayerName2
{
get { return playerName2; }
}
```
### メソッドの定義について
* メソッドはパスカルケースで定義します
* 引数とローカル変数はローワーキャメルケースで定義します
* メソッドには必ずコメントを記述します
* メソッドには必ずアクセス修飾子を付けます
```c#
/// <summary>
/// ダメージを与える
/// </summary>
/// <param name="damage">ダメージ値</param>
/// <returns></returns>
private int HitDamage(int damage)
{
var v = hp - damage;
return Mathf.Max(v, 0);
}
```
### enumの定義について
* enumはパスカルケースで定義します
```c#
namespace Player
{
public enum Condition
{
Fine,
Caution,
Danger,
Poison,
}
}
```
### インターフェイスの定義について
* インターフェイスはパスカルケースで記述します
* インターフェイスの頭文字にIを付けます
* メソッドは自動でpublicになるのでアクセス修飾子は省略します
```c#
namespace Player
{
interface IUnit
{
void HitDamage();
}
}
```
***
## レイアウト規則について
* インデントはタブ文字を使わず、スペース4つで行います
```c#
if(flg){
// 空白4文字でインデントを合わせる
int a = 0;
}
```
* 1つの行に1つのステートメントのみを記述します
```c#
// 良い例
AttackFunc1();
AttackFunc2();
// 悪い例
AttackFunc1(); AttackFunc2();
```
* 1つの行に1つの宣言のみを記述します
```c#
// 良い例
int x = 0;
int y = 0;
// 悪い例
int x,y;
```
* 1行の処理を改行する場合は、改行後にタブ(4つの空白)を入れます
```c#
var touchStartPos = new Vector3(Input.mousePosition.x,
Input.mousePosition.y,
Input.mousePosition.z);
```
* ORやAND条件式では複数の条件を()で囲みます
```c#
if ((val1 > val2) &&
(val1 > val3)) {
// true
}
```
* 次の例のように、装飾名が長い場合は、ドット(.)の後で改行します
```c#
var currentPerformanceCounterCategory = new System.Diagnostics.
PerformanceCounterCategory();
```
***
## コメント規則について
* 変数のコメントは宣言の横に記述し、処理のコメントは処理の一行上に記述します
* コメントは「//」の後に半角スペース1つを入れてから記述します
```c#
Vector3 nowPos; // 現在地
// カメラの回転
Vector3 angle = Camera.main.transform.rotation.eulerAngles;
Camera.main.transform.rotation = Quaternion.identity;
```
* 関数のコメントはドキュメンテーションコメント(///)で記述します
* ドキュメンテーションコメントは、関数の上の行で「///」と入力することで、自動で追加されます
```c#
/// <summary>
/// 配列に入ったデータの平均値と分散を求める
/// <param name="data">与えられたデータ列</param>
/// <param name="mean">dataの平均値(出力)</param>
/// <param name="variance">dataの分散(出力)</param>
/// </summary>
private void CalcMean(int[] data, out double mean, out double variance) {
// 適切な処理。
}
```
***
## 頭字語を使った命名について
* UIやIPなど複数の単語からなる頭字語は大文字で記述します
```c#
private UIManager UIManager {get; set;}
private UIManager playerUI;
private int networkIPAddress;
```
* ただし、例外としてID(<span style="color: red;">id</span>entification)やOKなど単語の先頭2文字からなる頭字語はパスカルケースで記述します
```c#
private int id;
private int playerId;
private bool isOk;
```
* XmlやHttpなど3文字以上の頭字語は頭文字のみ大文字で記述します
```c#
private XmlManager XmlManager {get; set;}
private XmlManager playerXml;
private int xmlHttpRequestCode = 0;
```
***
## 暗黙の型指定について
* 型名が長く定義が冗長な場合は、varを使用して簡潔にします
```c#
// 冗長な定義
Dictionary<GameObject, Vector3>() gameObjPosList = new Dictionary<GameObject, Vector3>();
// varを使用した簡潔な定義
var gameObjPosList = new Dictionary<GameObject, Vector3>();
```
***
## オブジェクト初期化子について
* オブジェクト初期化子を使用してオブジェクトの作成を簡略化します
* オブジェクト初期化子を使用する事で、可読化と記述ミス防止に繋がります
```c#
// 冗長な定義
var instance1 = new ExampleClass();
instance1.name = "Desktop";
instance1.id = 37414;
instance1.location = "Redmond";
instance1.age = 2.3;
// オブジェクト初期化子を使用した簡潔な定義
var instance2 = new ExampleClass {
name = "Desktop",
id = 37414,
location = "Redmond",
age = 2.3};
```
***
## 文字の連結について
* 文字の結合方法はいくつか種類があります
| 手法 | 可読性 | 速度処理<br>連結数=>小 | 処理速度<br>連結数=>大 | 記述例 |
| :--- | :---: | :---: | :---: | :--- |
| 文字列補間式 | 〇 | 〇 | 〇 | ``` string s = $"{hp}/{maxHp}"; ``` |
| string.Concat| △ | ○ | ○ | ``` string s = string.Concat(hp, "/", maxHp); ``` |
| +演算子| △ | 〇 | × | ``` string s = hp.ToString() + "/" + maxHp.ToString(); ``` |
| string.Format | × | △ | △ | ``` string s = string.Format("{0}/{1}", hp, maxHp); ``` |
* 文字列を連結する場合は文字列補間式を使用する
```c#
int hp = 10;
int maxHp = 30;
string s = $"HP: {hp}/{maxHp}"; // HP: 10/30
```
* 長文の文字列を作成する場合はStringBuilderを使用する
```c#
StringBuilder sb = new StringBuilder();
sb.Append("長文1");
sb.Append("長文2");
sb.Append("長文3");
string s = sb.ToString(); // 長文1長文2長文3
```
***
## 更新履歴
* 2021年2月22日 「頭字語を使った命名について」を修正
以上