C# 風格指南
明確且一致的程式編寫慣例對每個專案都很重要,Godot 也不例外。
本頁包含了程式風格指南,Godot 的開發者與貢獻者都會遵循。因此,這份指南主要是給想要貢獻 Godot 專案的人。但因為本文所列的慣例與指引也是該語言最廣泛採用的寫法,我們也鼓勵你參考採用,尤其如果你還沒有一份自己的風格指南時。
備註
本文章並非一份涵蓋所有標準程式設計慣例或最佳實踐的完整指南。如果你對本文未涵蓋的部分感到疑慮,請參考更完整的說明文件,例如 C# 編碼慣例 或 Framework 設計指引 。
語言規範
Godot 目前在引擎與範例程式碼中使用 C# 12.0 版,這是因為 .NET 8.0(目前的基本需求)所支援的版本。因此,在升級到新版本前,應避免混用僅在 C# 13.0 或更新版本才有的語言功能。
更多關於不同 C# 版本功能的資訊,請參考 C# 新功能 。
格式
通用指引
換行時請使用 LF 字元,不要用 CRLF 或 CR。
除了 csproj 檔案外,每個檔案結尾請用一個 LF 換行字元。
請使用無 BOM 的 UTF-8 編碼。
縮排請使用 4 個空白字元,不要用 Tab 字元(這稱為「軟 Tab」)。
當一行超過 100 個字元時,建議拆成多行。
換行與空白行
一般縮排建議遵循 Allman 風格 ,也就是將控制敘述的大括號放在下一行,並與該行縮排對齊:
// Use this style:
if (x > 0)
{
DoSomething();
}
// NOT this:
if (x > 0) {
DoSomething();
}
但你可以在以下情況省略大括號內的換行:
用於簡單的屬性存取子。
用於簡單的物件、陣列或集合初始值。
用於抽象自動屬性、索引子或事件宣告。
// You may put the brackets in a single line in following cases:
public interface MyInterface
{
int MyProperty { get; set; }
}
public class MyClass : ParentClass
{
public int Value
{
get { return 0; }
set
{
ArrayValue = new [] {value};
}
}
}
應插入空行的情況:
在
using陳述式列表之後。在方法、屬性與內部型別宣告之間。
在每個檔案的結尾。
欄位與常數的宣告可以根據相關性分組。這種情況下,建議在不同群組間插入空行以方便閱讀。
應避免插入空行的情況:
在
{左大括號之後。在
}右大括號之前。在註解區塊或單行註解之後。
在另一個空行旁邊時。
using System;
using Godot;
// Blank line after `using` list.
public class MyClass
{ // No blank line after `{`.
public enum MyEnum
{
Value,
AnotherValue // No blank line before `}`.
}
// Blank line around inner types.
public const int SomeConstant = 1;
public const int AnotherConstant = 2;
private Vector3 _x; // Related constants or fields can be
private Vector3 _y; // grouped together.
private float _width;
private float _height;
public int MyProperty { get; set; }
// Blank line around properties.
public void MyMethod()
{
// Some comment.
AnotherMethod(); // No blank line after a comment.
}
// Blank line around methods.
public void AnotherMethod()
{
}
}
空白字元使用
應插入空白字元的情況:
在二元與三元運算子兩側。
在左括號與
if、for、foreach、catch、while、lock或using關鍵字之間。在單行存取子區塊之前與區塊內。
在單行存取子區塊的存取子之間。
在不是行尾的逗號後方。
在
for陳述式中的分號之後。在單行
case陳述式的冒號之後。在型別宣告中的冒號兩側。
在 Lambda 箭頭的兩側。
在單行註解符號(
//)之後,若用於行尾則也要在前面加空白。於單行初始化式中,在左大括號之後與右大括號之前插入空白字元。
以下情形不使用空白字元:
在型別轉換的括號後方。
以下範例根據上述慣例展示了正確的空白字元用法:
public class MyClass<A, B> : Parent<A, B>
{
public float MyProperty { get; set; }
public float AnotherProperty
{
get { return MyProperty; }
}
public void MyMethod()
{
int[] values = { 1, 2, 3, 4 };
int sum = 0;
// Single line comment.
for (int i = 0; i < values.Length; i++)
{
switch (i)
{
case 3: return;
default:
sum += i > 2 ? 0 : 1;
break;
}
}
i += (int)MyProperty; // No space after a type cast.
}
}
命名慣例
所有命名空間、型別名稱以及成員層級識別子(如方法、屬性、常數、事件)都使用 PascalCase,Private 欄位除外:
namespace ExampleProject
{
public class PlayerCharacter
{
public const float DefaultSpeed = 10f;
public float CurrentSpeed { get; set; }
protected int HitPoints;
private void CalculateWeaponDamage()
{
}
}
}
其他所有識別子(如區域變數、方法參數)請用 camelCase。Private 欄位請在前面加底線(_)(但方法與屬性不加,如上所述):
private Vector3 _aimingAt; // Use a `_` prefix for private fields.
private void Attack(float attackStrength)
{
Enemy targetFound = FindTarget(_aimingAt);
targetFound?.Hit(attackStrength);
}
有個例外,像 UI 這種只有兩個字母的縮寫,在需要 PascalCase 的場合請用全大寫,其餘情況請用小寫。
請注意,id 不是 縮寫,應當作一般識別子處理:
public string Id { get; }
public UIManager UI
{
get { return uiManager; }
}
一般不建議用型別名稱作為識別子的前綴,例如 string strText 或 float fPower。不過介面是例外,介面名稱前面 應該 加上大寫的 I,如 IInventoryHolder 或 IDamageable。
最後,請盡量選擇具描述性的名稱,不要為了簡短而犧牲可讀性。
舉例來說,如果你要寫尋找鄰近敵人並用武器攻擊的程式,建議這樣命名:
FindNearbyEnemy()?.Damage(weaponDamage);
而不是:
FindNode()?.Change(wpnDmg);
成員變數
如果某個變數只會在一個方法內使用,不要把它宣告成成員變數。這會讓程式碼難以追蹤。請直接在方法內宣告為區域變數。
區域變數
區域變數請盡量在首次使用的附近宣告。這樣能讓程式碼更易閱讀,也不用頻繁捲動去尋找變數的宣告位置。
隱含型別區域變數
建議可以用隱含型別(var)宣告區域變數,但**僅限於型別能從指派右側明確判斷時**:
// You can use `var` for these cases:
var direction = new Vector2(1, 0);
var value = (int)speed;
var text = "Some value";
for (var i = 0; i < 10; i++)
{
}
// But not for these:
var value = GetValue();
var velocity = direction * 1.5;
// It's generally a better idea to use explicit typing for numeric values, especially with
// the existence of the `real_t` alias in Godot, which can either be double or float
// depending on the build configuration.
var value = 1.5;
其他注意事項
請使用明確的存取修飾詞。
請用屬性取代非 private 欄位。
修飾詞的順序應為:
public/protected/private/internal/virtual/override/abstract/new/static/readonly。不必要時請避免對成員用完整限定名稱或
this.前綴。請移除未使用的
using陳述式與不必要的括號。可省略型別的預設初值。
建議使用 null 條件運算子或型別初始化式讓程式碼更精簡。
當數值有可能是不同型別時請用安全轉型,否則可用直接轉型。