理解方法和使用 C# 擴展方法
在C#程式設計中,方法是封裝可重用程式碼並執行特定任務的重要構建塊。 它們可以接受參數、返回值,並通過重載來處理不同的輸入。 更高級的概念是,擴充方法使開發者能夠向現有類型添加功能,包括那些他們無法控制的類型。
Tim Corey 的影片 '如何在C#中創建擴充方法' 是一個很好的資源。 在本指南中,我們將探討Tim涵蓋的幾個主題:
- 定義和調用方法
- 方法參數和引數
- 方法回傳值
- 方法重載
- 實現擴充方法
定義和調用方法
實例方法的定義
在C#中,一個方法是在類內定義的。 方法定義的一般語法包括訪問修飾符、返回類型、方法名和參數。
public class SampleClass
{
public void SampleMethod()
{
// Method implementation
}
}
public class SampleClass
{
public void SampleMethod()
{
// Method implementation
}
}
在4:05的Tim Corey's示例中,他在一個靜態類中定義了一個方法以創建擴充方法。 定義的方法是 PrintToConsole。 定義包含了所有一般語法,清晰地解釋了如何用一個實用的例子來定義一個方法:
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}
調用方法
'方法調用'是告訴程式執行在程式碼的其它地方定義的特定方法,執行一個預定義的動作。 方法是通過類實例調用的,或者如果它們是靜態方法,則直接調用。 對於擴充方法,它們看起來就像是它們所擴展類型的一部分。 在視頻的6:18,Tim展示了如何像預定義方法一樣用基本數據類型調用一個擴充方法。
string demo = "This is a demo";
demo.PrintToConsole(); // Extension method call
string demo = "This is a demo";
demo.PrintToConsole(); // Extension method call
方法參數和引數
參數
參數是在方法定義中指定的,作為傳遞到方法中的值的佔位符。 您可以在這裡看到在調用 WriteLine 方法後,而 message 是參數。
public void DisplayMessage(string message)
{
Console.WriteLine(message);
}
public void DisplayMessage(string message)
{
Console.WriteLine(message);
}
另外,在Tim Corey在4:05給出的擴充方法示例中,message 是參數:
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
引數
引數是調用方法時實際傳遞給方法的值。
DisplayMessage("Hello, World!"); // "Hello, World!" is the argument
DisplayMessage("Hello, World!"); // "Hello, World!" is the argument
當Tim Corey在6:20調用該方法時使用字串類型的點語法時,字串值實際上作為值傳遞給 PrintToConsole 方法:
string demo = "This is a demo";
demo.PrintToConsole(); // "This is a demo" is the argument
string demo = "This is a demo";
demo.PrintToConsole(); // "This is a demo" is the argument
方法回傳值
方法可以使用return語句返回值。 返回類型是在方法簽名中指定的。
public int Add(int a, int b)
{
return a + b;
}
public int Add(int a, int b)
{
return a + b;
}
雖然Tim Corey的視頻中的擴充方法沒有返回值(void返回類型),但您可以創建帶返回值的擴充方法。 Tim的示例中的返回類型是void,這意味著該方法不返回任何值。 以下示例顯示如何返回一個值:
public static int WordCount(this string str)
{
return str.Split(' ').Length;
}
public static int WordCount(this string str)
{
return str.Split(' ').Length;
}
方法重載 (11:15)
方法重載允許多個具有相同名稱但不同參數的方法存在。 這對創建靈活且直觀的API很有用。
public void Display(string message)
{
Console.WriteLine(message);
}
public void Display(int number)
{
Console.WriteLine(number);
}
public void Display(string message)
{
Console.WriteLine(message);
}
public void Display(int number)
{
Console.WriteLine(number);
}
Tim Corey在11:24簡要介紹了為不同日誌場景創建多個方法,這可以被視為更廣泛意義上的方法重載示例。 日誌方法存在兩次,一個帶一個參數,另一個有兩個參數。 在11:39的第二個日誌方法是日誌方法的重載版本,賦予它多種功能,在相同名稱下。
Implementing Extension Methods in C
什麼是擴充方法? (3:13)
擴充方法允許您向現有類型添加新方法,而無需修改或重新編譯它們。 雖然它們被調用時就像實例方法一樣,但擴充方法是定義為靜態的。
創建擴充方法
在前一節中'定義和調用方法',我們強調了如何在一個單獨的靜態類中創建一個擴充方法,並在其中定義靜態方法以用作擴充方法。 以下是Tim Corey強調的一些關鍵點:
- 確保定義一個單獨的公共靜態類,或者,如Tim所說,"將類標記為靜態,否則它將無法工作。"
- 當您創建更多的擴充方法時,按類型分組它們 (3:43)
- 定義一個靜態方法,第一個參數前綴
this關鍵字,指定要擴展的類型 (4:58)
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}
調用擴充方法 (6:18)
接下來,Tim展示了如何在這個字串變數上調用擴充方法:
demo.PrintToConsole();
demo.PrintToConsole();
當您輸入 demo 並開始鍵入 Print 時,IntelliSense會建議 PrintToConsole 方法。 這是添加到 string 類型的新方法。
方法調用如何工作 (6:30)
Tim解釋為何您可以調用 demo.PrintToConsole():
- Demo是一個字串類型:變數
demo是string的類型。 - 擴展字串類型:
string類型已通過新方法PrintToConsole進行擴展。
理解參數 (6:41)
儘管似乎未向 PrintToConsole 方法傳遞任何參數,但Tim指出隱式參數傳遞 - demo 字串作為擴充方法的第一個參數傳遞。
Tim強調擴充方法在調用時比其定義時少了一個參數。 這是因為第一個參數(被擴展的類型)是隱式的。
擴充方法的簽名
這裡,this string message 意味著方法擴展了 string 類型,message 是隱式參數:
public static void PrintToConsole(this string message)
public static void PrintToConsole(this string message)
執行程式碼 (7:08)
最後,當調用方法 PrintToConsole 時,它將字串輸出到控制台:
Console.WriteLine(message);
Console.WriteLine(message);
因此,調用 demo.PrintToConsole() 會將 "這是一個展示" 印到控制台。
對第三方類使用擴充方法
擴展第三方類 (10:59)
Tim Corey解釋說擴充方法可以擴展任何類型,即使是您無法直接修改的第三方類別。 例如,讓我們看看在11:09的 SimpleLogger 類。
這裡,Tim使用假設的第三方類 SimpleLogger 記錄消息到控制台 (11:09)。 該類有兩個方法:
public class SimpleLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
public void Log(string message, string messageType)
{
Console.WriteLine($"{messageType}: {message}");
}
}
public class SimpleLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
public void Log(string message, string messageType)
{
Console.WriteLine($"{messageType}: {message}");
}
}
這些方法不太理想,因為消息類型是一個簡單的字串,這可能導致不一致。 Tim建議創建擴充方法以改進該類。
實現一致的消息類型
使用擴充方法能確保持續性地使用相同的消息類型和格式,提高代碼一致性。 在(12:40),Tim創建了一個靜態類 ExtendSimpleLogger:
public static class ExtendSimpleLogger
{
public static void LogError(this SimpleLogger logger, string message)
{
logger.Log(message, "Error");
}
public static void LogWarning(this SimpleLogger logger, string message)
{
logger.Log(message, "Warning");
}
}
public static class ExtendSimpleLogger
{
public static void LogError(this SimpleLogger logger, string message)
{
logger.Log(message, "Error");
}
public static void LogWarning(this SimpleLogger logger, string message)
{
logger.Log(message, "Warning");
}
}
使調用更一致
手頭上有此程式 (14:02),他現在可以在 SimpleLogger 實例上調用擴充方法:
SimpleLogger logger = new SimpleLogger();
logger.LogError("This is an error");
logger.LogWarning("This is a warning");
SimpleLogger logger = new SimpleLogger();
logger.LogError("This is an error");
logger.LogWarning("This is a warning");
這確保了消息類型始終是'錯誤'和'警告'。
增強輸出格式 (14:35)
Tim增加功能以設置錯誤消息的控制台文字顏色,確保它們突出顯示:
public static void LogError(this SimpleLogger logger, string message)
{
var defaultColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
logger.Log(message, "Error");
Console.ForegroundColor = defaultColor;
}
public static void LogError(this SimpleLogger logger, string message)
{
var defaultColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
logger.Log(message, "Error");
Console.ForegroundColor = defaultColor;
}
與直接方法調用進行比較 (17:21)
Tim將此方法與直接調用原始 Log 方法進行比較,這可能會導致不一致:
logger.Log("Test error", "Error");
logger.Log("Another error", "ERROR");
logger.Log("Test error", "Error");
logger.Log("Another error", "ERROR");
此方法容易出現拼寫錯誤和不一致的格式。
鏈接擴充方法 (18:13)
Tim演示了如何鏈接擴充方法以使代碼更具可讀性:
public static void LogInfo(this SimpleLogger logger, string message)
{
logger.Log(message, "Info");
}
public static void SaveToDatabase(this SimpleLogger logger)
{
// Simulate saving to a database
}
public static void LogInfo(this SimpleLogger logger, string message)
{
logger.Log(message, "Info");
}
public static void SaveToDatabase(this SimpleLogger logger)
{
// Simulate saving to a database
}
現在,您可以鏈接這些方法:
logger.LogInfo("Information").SaveToDatabase();
logger.LogInfo("Information").SaveToDatabase();
與嵌套方法調用相比,這使得代碼更易讀和直觀:
SaveToDatabase(LogInfo(logger, "Information"));
SaveToDatabase(LogInfo(logger, "Information"));
通過使用點符號和鏈接,代碼的意圖變得更清晰且不那麼嵌套。
擴展您不擁有的事物
在20:13,Tim Corey解釋擴充方法非常適合添加功能到您不擁有的類,如第三方函式庫。 這允許無需修改原始代碼進行增強。
避免依賴
Corey也強調使用擴充方法引入依賴而不將它們直接與類耦合。 例如,添加數據庫保存功能到 Person 類,而不嵌入數據庫邏輯。
擴展介面
擴充方法也可以應用於介面,如21:30所述,使實現該介面的多個類可以共享相同的功能。 這促進了代碼重複使用和簡化。
何時不使用擴充方法
在23:03,Tim Corey建議避免過度使用擴充方法,尤其是與基本或由Microsoft提供的類型,以防止混亂和複雜性。 謹慎使用,僅在有明顯好處時使用。
開放/封閉原則
在24:54-25:40之間的部分中,Tim強調通過使用擴充方法來遵循開放/封閉原則,從而在不修改現有穩定代碼的情況下增加新功能,從而減少引入錯誤的風險。
使用語句的最佳實踐
通過合乎邏輯的分組來組織擴充方法,並將其放置在單獨的命名空間中,以避免命名衝突並促進更易於維護和調試。
結論
這裡您就了解了定義與調用方法,處理參數和回傳值並利用方法重載的基礎知識。 藉此,您可以在C#中構建強大而靈活的應用程式。
如Tim Corey所解釋,擴充方法提供了一種強大方式來增強現有類型,並使您的代碼更加可讀和易於維護。 有關更詳細的見解和實際範例,您可以觀看Tim Corey的完整視頻 如何在C#中創建擴充方法。
