C# Extension Methods

2023-03-13

C# Extension Methods (擴充方法) 是一種極具彈性和可擴展性的技術,它可以為現有的 Type 添加新的方法,而不需要修改原本的 Type 所在的 Class。

logo

說明

情境對話

嗨,你對 C# 的 Extension Methods 有沒有聽過?

嗯,有聽過,但不太了解它們是什麼。

Extension Methods 是 C# 中的一種特殊方法,它們可以讓你在不修改原始程式碼的情況下,擴展現有的類別或介面。這個特性在開發大型應用程式時非常有用。

這聽起來很不錯。但為什麼我們需要使用 Extension Methods 呢?

好問題。首先,它們可以讓你更容易地重用程式碼。比如說,如果你經常需要對字串進行一些類型轉換或者其他操作,你可以創建一個專門處理字串的 Extension Method,然後在你的應用程式中任何需要使用這些操作的地方都可以輕鬆地使用這個方法。

這確實可以節省很多時間。

對的,而且 Extension Methods 可以讓你更清晰地組織程式碼。通過將相關的方法放在一個擴展方法中,你可以使你的程式碼更易於維護和理解。

那 Extension Methods 會影響程式碼的效能嗎?

好問題。其實 Extension Methods 在效能方面影響非常小。當你調用一個擴展方法時,實際上是將方法的調用轉換為對靜態方法的調用。這意味著擴展方法的效能與常規靜態方法相當。

範例

使用 Extension Methods 的方法是建立新的靜態類別 (例如 StringExtensions),並且加入新的靜態方法 (例如 ToInt),並且在此靜態方法的第一個參數,使用 this 關鍵字,指出要擴充的 Type。

public static class StringExtensions
{
    public static int ToInt(this string str)
    {
        int result;
        int.TryParse(str, out result);
        return result;
    }
}

string str = "123";
int intValue = str.ToInt();
public static class ListExtensions
{
    public static bool IsNullOrEmpty<T>(this List<T> list)
    {
        return list == null || list.Count == 0;
    }
}

List<int> list = null;
bool isNullOrEmpty = list.IsNullOrEmpty();
public static class DateTimeExtensions
{
    public static string ToShortDate(this DateTime dateTime)
    {
        return dateTime.ToShortDateString();
    }
}

DateTime dateTime = DateTime.Now;
string shortDate = dateTime.ToShortDate();

Linq 應用

C# 的 LINQ (Language Integrated Query) 是一種強大的工具,可以將資料查詢和轉換整合到 C# 程式碼中。而 Extension Methods 可以用來擴充 LINQ 操作,這樣可以讓我們在 LINQ 查詢中使用自定義方法,使 LINQ 的應用範圍更加靈活。

以下是一個範例,展示如何使用 Extension Methods 擴充 LINQ 的 Where() Operator。

首先,我們需要創建一個靜態類別,包含我們要定義的 Extension Method。在這個例子中,我們定義了一個名為 WhereIf() 的方法,它接受一個 boolcondition 和一個 Func<TSource, bool> 委託 predicate

using System;
using System.Collections.Generic;
using System.Linq;

public static class LinqExtensions
{
    public static IEnumerable<TSource> WhereIf<TSource>(
        this IEnumerable<TSource> source, 
        bool condition, 
        Func<TSource, bool> predicate)
    {
        if (condition)
        {
            return source.Where(predicate);
        }
        else
        {
            return source;
        }
    }
}

在這個 Extension Method 中,我們首先檢查 condition 的值。如果為 true,則使用 LINQ 的 Where() Operator來過濾序列,並返回過濾後的結果。如果 conditionfalse,則直接返回原始序列。

現在,我們可以在 LINQ 查詢中使用 WhereIf() 方法。例如:

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
bool condition = true;
int threshold = 3;

var result = numbers
    .WhereIf(condition, n => n > threshold)
    .Select(n => n * 10);

foreach (var item in result)
{
    Console.WriteLine(item);
}

在這個範例中,我們創建了一個名為 numbers 的整數列表,並定義了一個名為 conditionbool 變數,以及一個名為 threshold 的閾值。

然後,我們使用 WhereIf() 方法來過濾列表,只保留大於 threshold 的元素,如果 conditionfalse,則直接返回原始列表。最後,我們使用 Select() 將序列中的每個元素乘以 10。

總而言之 Extension Methods 可以讓我們更加靈活地擴展 LINQ Operator,這對於編寫可重用的 LINQ 查詢非常有用。

業界應用

C# Extension Methods | GitHub 的開源專案中,將各種實用但原生 C# 未提供的方法加入為 Extension Methods,以 Nuget 安裝之後,原本的 C# 就像是多了一對翅膀,寫起來如虎添翼更為行雲流水。

其中一個範例是原本 C# 有提供 Array 的 Exists 方法,但必須使用靜態類別的方式呼叫使用:

Array.Exists(new string[] { "Mercury", "Venus", "Earth", "Mars", "Jupiter"}, "Earth")

但在 C# Extension Methods 的 Array - Exists 則將它擴充為 Extensino Methods,只需要直接在 array instance 上使用即可,用起來直觀也易於理解 😀

new string[] { "Mercury", "Venus", "Earth", "Mars", "Jupiter"}.Exists("Earth");

C# Extension Methods - Array - Exists.cs

public static partial class Extensions
{
    /// <summary>
    ///     A T[] extension method that exists.
    /// </summary>
    /// <typeparam name="T">Generic type parameter.</typeparam>
    /// <param name="array">The array to act on.</param>
    /// <param name="match">Specifies the match.</param>
    /// <returns>true if it succeeds, false if it fails.</returns>
    public static Boolean Exists<T>(this T[] array, Predicate<T> match)
    {
        return Array.Exists(array, match);
    }
}