跳至页脚内容
Iron Academy Logo
学习 C#
学习 C#

其他类别

理解方法和使用 C# 扩展方法

Tim Corey
28m 27s

在 C# 编程中,方法是重要的构建模块,用于封装可重用代码并执行特定任务。 它们可以接受参数、返回值,并且可以被重载以处理不同的输入。 扩展方法是一种更高级的概念,它允许开发人员向现有类型(包括他们无法控制的类型)添加功能。

Tim Corey的视频"如何在 C# 中创建扩展方法"是一个非常好的资源。 在本指南中,我们将探讨蒂姆涉及的几个主题:

  1. 定义和调用方法
  2. 方法参数和参数
  3. 方法返回值
  4. 方法重载
  5. 实现扩展方法

定义和调用方法

已定义实例方法

在 C# 中,方法是在类中定义的。 方法定义的通用语法包括访问修饰符、返回类型、方法名称和参数。

public class SampleClass
{
    public void SampleMethod()
    {
        // Method implementation  
    }
}
public class SampleClass
{
    public void SampleMethod()
    {
        // Method implementation  
    }
}

在 Tim Corey 4 分 05 秒的示例中,他定义了一个静态类中的方法来创建一个扩展方法。 定义的方法是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

方法参数和实参

参数

参数在方法定义中指定,并作为传递给方法的值的占位符。 在调用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 简要地谈到了为不同的日志记录场景创建多个方法,这可以看作是更广泛意义上的方法重载的一个例子。 log 方法有两个版本,一个版本有一个参数,另一个版本有两个参数。 11:39 处的第二个日志方法是日志方法的重载版本,它以相同的名称提供了多种功能。

Implementing Extension Methods in C

什么是扩展方法? (3:13)

扩展方法允许你向现有类型添加新方法,而无需修改或重新编译它们。 虽然它们被称作实例方法,但扩展方法被定义为静态方法。

创建扩展方法

在上一节"定义和调用方法"中,我们重点介绍了 Tim Corey 如何在单独的静态类中创建扩展方法,并在其中定义静态方法以用作扩展方法。 以下是蒂姆·科里强调的一些关键点:

  1. 务必定义一个单独的公共静态类,或者,正如 Tim 所说,"将类标记为静态,否则它将无法工作。"
  2. 创建更多扩展方法时,请按类型对它们进行分组 (3:43)
  3. 定义一个静态方法,第一个参数以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();

当输入PrintToConsole方法。 这是添加到string类型的新方法。

方法调用的工作原理(6:30)

Tim解释了为什么您可以调用demo.PrintToConsole()

  • Demo是一个字符串类型:变量string类型。
  • 扩展的字符串类型PrintToConsole进行了扩展。

理解参数(6:41)

虽然似乎没有参数传递给demo字符串作为第一个参数传递给扩展方法。

Tim 强调,扩展方法在调用时比其定义中少一个参数。 这是因为第一个参数(被扩展的类型)是隐式的。

扩展方法签名

在这里,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()会将"This is a demo"打印到控制台。

使用第三方类的扩展方法

扩展第三方类(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# 中创建扩展方法的完整视频。

Hero Worlddot related to 理解方法和使用 C# 扩展方法
Hero Affiliate related to 理解方法和使用 C# 扩展方法

分享您的所爱,赚取更多收入

您为使用 .NET、C#、Java、Python 或 Node.js 的开发人员创建内容吗?将您的专业知识转化为额外收入!

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我