扩展方法
定义
扩展方法(Extension Methods)是C#中一种特殊的静态方法,它定义在一个静态类中,但是可以像实例方法一样被调用,使得代码更加简洁、易读。
设计目的
是为了给已有的类型添加新的行为,而不需要修改这些类型的原始定义。
特点
扩展方法有以下特点:
- 它必须在一个静态类中定义。
- 它必须有至少一个参数。
- 第一个参数必须有this前缀,并且指定了要扩展的类型。
- 第一个参数不能有任何其他的修饰符(如out或ref)。
示例一:
下面是一个扩展方法的示例,这个方法会在string类型上添加一个新的扩展方法,实现将字符串转换为全部大写的功能:
定义扩展方法
public static class ExtensionMethods
{
public static string ToUpperCase(this string str)
{
return str.ToUpper();
}
}
使用扩展方法
string original = "Hello, World!";
string upperCase = original.ToUpperCase();
Console.WriteLine(upperCase); // 输出 "HELLO, WORLD!"
Console.WriteLine("aaaa".ToUpperCase());
实际上,编译后,扩展方法调用就会翻译成普通的静态方法调用了
Console.WriteLine(ExtensionMethods.ToUpperCase("aaaa"));
示例二:
需要一个扩展方法来帮助我们计算字符串中某个子串出现的次数,并且还可以指定是否忽略大小写。
定义扩展方法
using System;
using System.Collections.Generic;
using System.Linq;
public static class StringExtensions
{
// 扩展方法,用于计算字符串中子串出现的次数
public static int CountOccurrences(this string source, string toFind, bool ignoreCase = false)
{
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(toFind))
return 0;
if (ignoreCase)
{
source = source.ToLower();
toFind = toFind.ToLower();
}
int count = 0;
int start = 0;
while ((start = source.IndexOf(toFind, start)) != -1)
{
count++;
start += toFind.Length;
}
return count;
}
}
在这个例子中,CountOccurrences 方法的第一个参数 source 是带有 this 关键字的,表示这个方法将扩展 string 类型。接下来的两个参数分别是 toFind 字符串和一个布尔值 ignoreCase,用于指示是否忽略大小写进行匹配。
使用扩展方法
接下来,我们可以在程序中使用这个扩展方法:
class Program
{
static void Main()
{
string text = "Hello world, hello everyone!";
string pattern = "hello";
// 计算不区分大小写的出现次数
int countIgnoreCase = text.CountOccurrences(pattern, true);
Console.WriteLine($"Pattern '{pattern}' occurs {countIgnoreCase} times (case-insensitive).");
// 计算区分大小写的出现次数
int countCaseSensitive = text.CountOccurrences(pattern, false);
Console.WriteLine($"Pattern '{pattern}' occurs {countCaseSensitive} times (case-sensitive).");
}
}
在这个示例中,我们创建了一个字符串 text 和一个子串 pattern,然后分别使用 CountOccurrences 方法来计算 pattern 在 text 中出现的次数,一次是忽略大小写的情况,一次是区分大小写的情况。
输出结果
当你运行这段代码时,应该会得到以下输出:
Pattern 'hello' occurs 2 times (case-insensitive).
Pattern 'hello' occurs 1 times (case-sensitive).
这个示例展示了如何定义一个带有多个参数的扩展方法,并且如何在实际应用中使用它。通过这种方式,你可以轻松地扩展现有类型的功能,同时保持代码的清晰和简洁。
注:接口也可以扩展
扩展方法链
定义
扩展方法链(Chaining Extension Methods)是指在一个表达式中连续使用多个扩展方法,从而使代码更加简洁和易读。这种方法在 C# 中非常常见,尤其是在处理集合和其他类型时。通过链式调用,你可以将多个操作串联在一起,形成流畅的代码风格。
示例
比如去除前后空白字符、转换为小写、替换某些字符等。我们可以定义一系列扩展方法,并将它们链式调用。
定义扩展方法
TrimAndToLower:去除前后空白字符并转换为小写。
ReplaceChars:替换字符串中的某些字符。
using System;
public static class StringExtensions
{
// 扩展方法:去除前后空白字符并转换为小写
public static string TrimAndToLower(this string str)
{
return str.Trim().ToLower();
}
// 扩展方法:替换字符串中的某些字符
public static string ReplaceChars(this string str, char oldChar, char newChar)
{
return str.Replace(oldChar, newChar);
}
}
使用扩展方法
class Program
{
static void Main()
{
string originalText = " Hello, World! ";
// 链式调用扩展方法
string processedText = originalText
.TrimAndToLower() // 去除前后空白字符并转换为小写
.ReplaceChars('!', '?'); // 替换 '!' 为 '?'
Console.WriteLine("Original Text: " + originalText);
Console.WriteLine("Processed Text: " + processedText);
}
}
输出结果
Original Text: Hello, World!
Processed Text: hello, world?
二义性与解析
命名空间
只有包含扩展方法的类在作用域内时(一般通过导入其所在的命名空间)我们才能够访问扩展方法。否则,编译时出错。
扩展方法与实例方法-优先级
任何兼容的实例方法的优先级总是高于扩展方法
示例
public static class ExtensionMethods
{
public static string ToUpperCase(this string str)
{
return str.ToUpper();
}
}
public class Test
{
public string ToUpperCase(this string str)
{
return str.ToUpper();
}
}
上例中,如果使用ToUpperCase方法会调用Test的
上例中,只能通过普通的静态调用语法调用扩展方法:及ExtensionMethods.ToUpperCase(...)
扩展方法与扩展方法-优先级
如果两个扩展方法签名相同,则扩展方法必须作为一个普通的静态方法调用才能进行区分。(方法签名相同:方法名称和参数列表【参数的数量、类型及参数的顺序】相同;方法签名不包括方法的返回类型,也不包括参数的名称)
使用更具体的参数的方法优先级更高。
public static class ExtensionMethods
{
public static string ToUpperCase(this string str)
{
。。。。。
}
}
public static class Test
{
public static string ToUpperCase(this object str)
{
。。。。。
}
}
下列代码将调用ExtensionMethods.ToUpperCase方法:
var a="aaaa".ToUpperCase();
注意:类型和结构体都比接口更加具体。
小白一枚~
大家一起学习~