C# 擴充方法(Extension Method)

C# 擴充方法是蠻早期提供的功能,讓指定型別的物件能夠使用額外自訂的方法,將不需要接露的部分隱藏、簡化流程程式碼。

  • 擴充方法必須定義在靜態類別內的靜態方法
  • 擴充方法至少需要一個參數,參數型別之前必須加上 this 關鍵字

範例

假設系統常使用 decimal 型別,且需要固定轉換成小數位四位,一般是這樣

1
2
3
decimal a = 0.1234567m;
Console.WriteLine(a.ToString("f4"));
// 0.1235

這樣做沒問題也達到需求,但會有個小缺點,就是整個系統會四處存在這種 hard code,除了不簡潔之外,萬一需求要改成五位,是不是就很麻煩了?

收斂

這種特殊功能的方法其實可以透過靜態類別來處理,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class DomainConvertHelper
{
public static string ConvertToF4(decimal val)
{
return val.ToString("f4");
}
}

public static void Main()
{
decimal a = 0.1234567m;
Console.WriteLine(DomainConvertHelper.ConvertToF4(a));
}

// 0.1235

透過 DomainConvertHelper 這個靜態類別就能夠做統一轉換。實務上不一定是這麼簡單內容,可能會加入 log 或者計時等功能。

這件事能透過擴充方法(extension method)再次進行簡化,還記得上面說到的,擴充方法使用上必須是靜態類別的靜態方法,同時替第一個參數加上this關鍵字,接著就能夠在該參數型別透過 . 找到擴充方法的使用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class ConvertHelper
{
public static string ConvertToF4(this decimal val)
{
return val.ToString("f4");
}
}

public static void Main()
{
decimal a = 0.1234567m;
Console.WriteLine(a.ConvertToF4());
}

// 0.1235

擴充方法使用上不需要太擔心,因為是編譯器以及編譯期就處理掉的,有興趣也可以看看IL內容。

其實今天想提這個主題是擴充方法的濫用,上面就是一個最佳的範例!

很多人會覺得這個做沒問題,系統就是很高頻率使用 decimal 轉成 string。

沒錯,但不是所有的 decimal 都有這樣的需求,會變成使用 decimal 型別的人都能夠呼叫 ConvertToF4 此擴充方法,萬一內容與開發者是不預期的就會很麻煩。以上面的例子來延伸討論,細心的人都有注意到程式碼最後我有附上程式產出結果是 0.1235,就是預設第五位數四捨五入。

如果今天我想要的結果是 0.1234,開發者誤用了 ConvertToF4 這個方法就會導致結果不預期,因此要極力避免不相關的型別擴充方法,原則很簡單:

  • 該型別是不是都需要使用此擴充方法

透過這個原則我們就能夠避免濫用擴充方法在不必要的型別上,而特定 domain 的操作應該還是保留在靜態方法內。

  • 作者: MingYi Chou
  • 版權聲明: 轉載不用問,但請請註明出處!本網誌均採用 BY-NC-SA 許可協議。