每位 C# 開發者都見過 #region,它能將程式碼區塊摺疊,讓檔案看起來整潔。但濫用 #region 往往掩蓋了程式碼品質問題。本文探討何時適合使用 #region,何時應改用重構手法。
public void DoSomething()
{
bool shouldIDoSomething;
#region Decide if I should do something
if (needToDoSomething && haventDoneSomethingThisDay)
shouldIDoSomething = true;
else
{
// 複雜邏輯決定 shouldIDoSomething
}
#endregion
if (shouldIDoSomething)
{
done++;
}
}
摺疊後雖然乾淨:
public void DoSomething()
{
bool shouldIDoSomething;
[Decide if I should do something]
if (shouldIDoSomething)
{
done++;
}
}
但這本質上是將一個函式內嵌在另一個函式中,違反「單一職責原則」。
public void DoSomething()
{
if (ShouldIDoSomething())
{
done++;
}
}
private bool ShouldIDoSomething()
{
if (needToDoSomething && haventDoneSomethingThisDay)
return true;
// 複雜邏輯...
return false;
}
優點:降低複雜度、可獨立測試、意圖更清晰。
小結 1:#region 不適合用在大型方法內。當你在方法中寫 #region 時,停下來思考:這段程式碼能否提取為獨立方法?大多數情況下,答案是肯定的。
#region Get Customer
public void GetCustomer()
{
// 取得客戶邏輯
}
#endregion
#region Save Customer
public void SaveCustomer()
{
// 儲存客戶邏輯
}
#endregion
摺疊後:
[Get Customer]
[Save Customer]
這樣反而降低可讀性:閱讀者必須逐一展開才能看程式碼。IDE 本身就有「摺疊所有方法」功能,不需要 #region 協助。
小結 2:不要因為「能用」就使用 #region。它無法消除複雜度,只是暫時隱藏。
public class PriceCalculator
{
public decimal CalculatePrice()
{
decimal price = 100m;
decimal discount = CalculateDiscount();
return price * (1m - discount);
}
#region Discount Calculation
private decimal CalculateDiscount()
{
decimal discount = 0m;
if (CanApplyDiscount())
discount = 0.05m;
return discount;
}
private bool CanApplyDiscount()
{
// 複雜邏輯...
}
// 更多折扣計算方法...
#endregion
}
這個類別有兩個職責:價格計算、折扣計算。#region 掩蓋了這個設計缺陷。
public class PriceCalculator
{
private readonly IDiscountCalculator _discountCalculator;
public PriceCalculator(IDiscountCalculator discountCalculator)
{
_discountCalculator = discountCalculator;
}
public decimal CalculatePrice()
{
decimal price = 100m;
decimal discount = _discountCalculator.Calculate();
return price * (1m - discount);
}
}
public interface IDiscountCalculator
{
decimal Calculate();
}
public class StandardDiscountCalculator : IDiscountCalculator
{
public decimal Calculate()
{
// 折扣邏輯...
}
}
符合單一職責原則,且便於測試與擴展。
小結 3:將一組相關方法提取到職責單一的新類別中,優於用 #region 分組。
在類別層級,用於組織結構性元素:
public class SomeClass
{
#region Events
// 事件定義
#endregion
#region Fields
// 私有欄位
#endregion
#region Properties
// 屬性
#endregion
#region Methods
// 方法
#endregion
#region Nested Types
// 巢狀類型
#endregion
}
摺疊後:
public class SomeClass
{
[Events]
[Fields]
[Properties]
[Methods]
[Nested Types]
}
這能幫助快速導覽類別結構,不影響程式碼品質。
當你寫出小巧、清晰、重點突出的方法和類別時,你甚至會發現 #region 是不必要的。