扩展方法 #

一、扩展方法概述 #

1.1 什么是扩展方法 #

扩展方法允许向现有类型添加方法,而无需修改原始类型。

1.2 扩展方法特点 #

  • 静态类中定义
  • 第一个参数用this修饰
  • 编译时绑定
  • 可扩展任何类型

二、定义扩展方法 #

2.1 基本语法 #

csharp
public static class StringExtensions
{
    public static string Reverse(this string str)
    {
        var chars = str.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
}

string text = "Hello";
string reversed = text.Reverse();

2.2 扩展方法参数 #

csharp
public static class StringExtensions
{
    public static string Repeat(this string str, int count)
    {
        return string.Concat(Enumerable.Repeat(str, count));
    }
}

string text = "Hi";
string repeated = text.Repeat(3);

2.3 扩展集合类型 #

csharp
public static class CollectionExtensions
{
    public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
    {
        foreach (var item in collection)
        {
            action(item);
        }
    }
    
    public static bool IsEmpty<T>(this IEnumerable<T> collection)
    {
        return !collection.Any();
    }
}

var numbers = new List<int> { 1, 2, 3 };
numbers.ForEach(n => Console.WriteLine(n));

var empty = new List<int>();
bool isEmpty = empty.IsEmpty();

三、常用扩展方法 #

3.1 字符串扩展 #

csharp
public static class StringExtensions
{
    public static bool IsNullOrEmpty(this string? str)
    {
        return string.IsNullOrEmpty(str);
    }
    
    public static bool IsNullOrWhiteSpace(this string? str)
    {
        return string.IsNullOrWhiteSpace(str);
    }
    
    public static string Truncate(this string str, int maxLength)
    {
        if (str.Length <= maxLength) return str;
        return str.Substring(0, maxLength) + "...";
    }
    
    public static string ToTitleCase(this string str)
    {
        return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
    }
}

string? name = null;
bool empty = name.IsNullOrEmpty();

string longText = "这是一段很长的文本内容";
string truncated = longText.Truncate(10);

3.2 数值扩展 #

csharp
public static class NumericExtensions
{
    public static bool IsEven(this int number)
    {
        return number % 2 == 0;
    }
    
    public static bool IsOdd(this int number)
    {
        return number % 2 != 0;
    }
    
    public static bool IsBetween(this int number, int min, int max)
    {
        return number >= min && number <= max;
    }
    
    public static string ToFileSize(this long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;
        
        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }
        
        return $"{size:0.##} {sizes[order]}";
    }
}

int num = 10;
bool even = num.IsEven();
bool inRange = num.IsBetween(1, 100);

long fileSize = 1024 * 1024;
string size = fileSize.ToFileSize();

3.3 日期扩展 #

csharp
public static class DateTimeExtensions
{
    public static bool IsWeekend(this DateTime date)
    {
        return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
    }
    
    public static bool IsToday(this DateTime date)
    {
        return date.Date == DateTime.Today;
    }
    
    public static int Age(this DateTime birthDate)
    {
        var today = DateTime.Today;
        var age = today.Year - birthDate.Year;
        if (birthDate.Date > today.AddYears(-age)) age--;
        return age;
    }
    
    public static DateTime StartOfWeek(this DateTime date, DayOfWeek startOfWeek = DayOfWeek.Monday)
    {
        int diff = (7 + (date.DayOfWeek - startOfWeek)) % 7;
        return date.AddDays(-diff).Date;
    }
}

DateTime date = DateTime.Now;
bool isWeekend = date.IsWeekend();

DateTime birthDate = new DateTime(1990, 5, 15);
int age = birthDate.Age();

四、扩展接口 #

4.1 扩展IEnumerable #

csharp
public static class EnumerableExtensions
{
    public static string JoinToString<T>(this IEnumerable<T> collection, string separator = ", ")
    {
        return string.Join(separator, collection);
    }
    
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> collection, Func<T, TKey> keySelector)
    {
        return collection.GroupBy(keySelector).Select(g => g.First());
    }
    
    public static void Apply<T>(this IEnumerable<T> collection, Action<T> action)
    {
        foreach (var item in collection)
        {
            action(item);
        }
    }
}

var numbers = new[] { 1, 2, 3, 4, 5 };
string joined = numbers.JoinToString("-");

var people = new[] { new { Name = "张三", Age = 25 }, new { Name = "李四", Age = 25 } };
var distinct = people.DistinctBy(p => p.Age);

五、扩展方法优先级 #

5.1 解析顺序 #

  1. 实例方法优先
  2. 当前命名空间的扩展方法
  3. 外部命名空间的扩展方法
csharp
public class MyClass
{
    public void DoSomething() { }
}

public static class MyClassExtensions
{
    public static void DoSomething(this MyClass obj) { }
}

var obj = new MyClass();
obj.DoSomething();

六、最佳实践 #

6.1 命名规范 #

csharp
public static class StringExtensions { }
public static class DateTimeExtensions { }
public static class EnumerableExtensions { }

6.2 适度使用 #

csharp
public static class StringExtensions
{
    public static string Reverse(this string str) { }
    public static string Truncate(this string str, int maxLength) { }
}

public static class StringParserExtensions
{
    public static bool TryParseInt(this string str, out int result) { }
}

七、总结 #

扩展方法要点:

要点 说明
静态类 必须在静态类中
this关键字 第一个参数
命名空间 需要引入
优先级 实例方法优先

下一步,让我们学习LINQ!

最后更新:2026-03-26