你是否经常遇到这样的痛点:明明一个简单的字符串判空操作,却要写一大串string.IsNullOrEmpty()?想给第三方类库添加几个实用方法,但又不能修改源码?或者看到Python那种链式调用的优雅写法,羡慕得不行?我记得这个.NET刚出这个功能时,我几乎把所有utils都重写了。
今天就来彻底解决这些问题!静态扩展方法(Extension Methods)是C# 3.0引入的一个强大特性,它能让你在不修改原始类型的情况下,为任何类型添加新方法。掌握这个技巧,你的代码将变得更加优雅、可读性更强,同时还能大幅提升开发效率!
c#// 传统写法:冗长且不直观
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrWhiteSpace(userName))
{
var result = StringHelper.FormatUserName(userName);
}
c#// 传统写法:嵌套调用,可读性差
var result = StringHelper.Trim(StringHelper.RemoveSpecialChars(userName.ToLower()));
你用的是别人的类库,想添加一些便捷方法,但无法修改源码。
c#namespace AppStaticExt
{
public static class StringExtensions
{
/// <summary>
/// 判断字符串是否有效(非空且非空白)
/// </summary>
public static bool IsValid(this string str)
{
return !string.IsNullOrEmpty(str) && !string.IsNullOrWhiteSpace(str);
}
/// <summary>
/// 安全截取字符串,超长自动添加省略号
/// </summary>
public static string Truncate(this string str, int maxLength, string suffix = "...")
{
if (string.IsNullOrEmpty(str)) return str;
if (str.Length <= maxLength) return str;
return str.Substring(0, maxLength - suffix.Length) + suffix;
}
/// <summary>
/// 转换为帕斯卡命名法(首字母大写)
/// </summary>
public static string ToPascalCase(this string str)
{
if (!str.IsValid()) return str;
return char.ToUpper(str[0]) + str.Substring(1).ToLower();
}
}
internal class Program
{
static void Main(string[] args)
{
// 使用示例
string userName = " john_doe ";
if (userName.Trim().IsValid())
{
var displayName = userName.Trim().ToPascalCase();
var shortName = displayName.Truncate(10);
Console.WriteLine(shortName);
}
}
}
}

💪 实际应用场景:用户输入验证、UI显示文本处理、API数据格式化
⚠️ 常见坑点:扩展方法的第一个参数可能为null,务必做null检查!
c#namespace AppStaticExt
{
public static class EnumerableExtensions
{
/// <summary>
/// 安全的ForEach操作,支持链式调用
/// </summary>
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException(nameof(source));
foreach (var item in source)
{
action(item);
}
return source;
}
/// <summary>
/// 判断集合是否为空或null
/// </summary>
public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
{
return source == null || !source.Any();
}
/// <summary>
/// 分批处理大集合,避免内存溢出
/// </summary>
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (batchSize <= 0) throw new ArgumentException("Batch size must be greater than 0");
var batch = new List<T>(batchSize);
foreach (var item in source)
{
batch.Add(item);
if (batch.Count == batchSize)
{
yield return batch;
batch = new List<T>(batchSize);
}
}
if (batch.Count > 0)
yield return batch;
}
}
internal class Program
{
static void Main(string[] args)
{
// 🚀 使用示例
var numbers = Enumerable.Range(1, 1000);
// 优雅的链式调用
numbers.Where(x => x % 2 == 0)
.Batch(10) // 每批10个
.ForEach(batch =>
{
Console.WriteLine($"Processing batch: {string.Join(", ", batch)}");
});
}
}
}

💪 实际应用场景:数据批处理、大集合操作、API分页处理
c#public static class DateTimeExtensions
{
/// <summary>
/// 获取友好的时间显示(如:刚刚、5分钟前、昨天)
/// </summary>
public static string ToFriendlyString(this DateTime dateTime)
{
var now = DateTime.Now;
var timeSpan = now - dateTime;
if (timeSpan.TotalMinutes < 1)
return "刚刚";
if (timeSpan.TotalMinutes < 60)
return $"{(int)timeSpan.TotalMinutes}分钟前";
if (timeSpan.TotalHours < 24)
return $"{(int)timeSpan.TotalHours}小时前";
if (timeSpan.TotalDays < 30)
return $"{(int)timeSpan.TotalDays}天前";
return dateTime.ToString("yyyy-MM-dd");
}
/// <summary>
/// 判断是否为工作日
/// </summary>
public static bool IsWorkingDay(this DateTime date)
{
return date.DayOfWeek != DayOfWeek.Saturday &&
date.DayOfWeek != DayOfWeek.Sunday;
}
/// <summary>
/// 获取月初和月末
/// </summary>
public static (DateTime Start, DateTime End) GetMonthRange(this DateTime date)
{
var start = new DateTime(date.Year, date.Month, 1);
var end = start.AddMonths(1).AddDays(-1);
return (start, end);
}
}

💪 实际应用场景:社交媒体时间显示、业务日期计算、报表统计
c#using System.Text.Json;
namespace AppStaticExt
{
public static class ObjectExtensions
{
/// <summary>
/// 对象深拷贝(通过JSON序列化实现)
/// </summary>
public static T DeepCopy<T>(this T obj) where T : class
{
if (obj == null) return null;
var json = JsonSerializer.Serialize(obj);
return JsonSerializer.Deserialize<T>(json);
}
/// <summary>
/// 将对象转换为字典(反射实现)
/// </summary>
public static Dictionary<string, object> ToDictionary(this object obj)
{
if (obj == null) return new Dictionary<string, object>();
return obj.GetType()
.GetProperties()
.Where(p => p.CanRead)
.ToDictionary(p => p.Name, p => p.GetValue(obj));
}
/// <summary>
/// 链式调用支持:对象配置
/// </summary>
public static T Configure<T>(this T obj, Action<T> configure) where T : class
{
configure?.Invoke(obj);
return obj;
}
}
// 🚀 使用示例
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var user = new User { Name = "张三", Age = 25, Email = "zhangsan@example.com" };
// 深拷贝
var userCopy = user.DeepCopy()
.Configure(u => u.Name = "李四"); // 链式配置
// 转字典
var userDict = user.ToDictionary();
Console.WriteLine(string.Join(", ", userDict.Select(kv => $"{kv.Key}={kv.Value}")));
}
}
}
💪 实际应用场景:对象克隆、动态属性访问、配置对象初始化
c#public static class NumericExtensions
{
/// <summary>
/// 数值范围限制
/// </summary>
public static T Clamp<T>(this T value, T min, T max) where T : IComparable<T>
{
if (value.CompareTo(min) < 0) return min;
if (value.CompareTo(max) > 0) return max;
return value;
}
/// <summary>
/// 百分比计算
/// </summary>
public static double ToPercentage(this double value, double total)
{
if (total == 0) return 0;
return Math.Round((value / total) * 100, 2);
}
/// <summary>
/// 金额格式化
/// </summary>
public static string ToMoney(this decimal amount, string currency = "¥")
{
return $"{currency}{amount:N2}";
}
/// <summary>
/// 数值是否在指定范围内
/// </summary>
public static bool IsBetween<T>(this T value, T min, T max) where T : IComparable<T>
{
return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
}
}

💪 实际应用场景:数据验证、财务计算、游戏开发、数据统计
c#// ✅ 好的做法:使用静态缓存
public static class CacheableExtensions
{
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertyCache
= new ConcurrentDictionary<Type, PropertyInfo[]>();
public static Dictionary<string, object> ToDictionaryFast(this object obj)
{
if (obj == null) return new Dictionary<string, object>();
var type = obj.GetType();
var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties());
return properties.Where(p => p.CanRead)
.ToDictionary(p => p.Name, p => p.GetValue(obj));
}
}
c#public static class SafeExtensions
{
/// <summary>
/// 安全的类型转换
/// </summary>
public static T SafeCast<T>(this object obj, T defaultValue = default(T))
{
try
{
if (obj is T result)
return result;
return (T)Convert.ChangeType(obj, typeof(T));
}
catch
{
return defaultValue;
}
}
}
⚠️ 重要提醒:
经过今天的学习,相信你已经掌握了C#静态扩展方法的精髓。让我们来回顾一下三个核心要点:
public static类 + this参数,就能为任意类型添加方法,让代码更具表达力掌握了这些技巧,你的C#代码将变得更加简洁优雅,开发效率也会大幅提升。记住,好的代码不仅要功能强大,更要让人读起来如诗如画!
💬 互动时间:
欢迎在评论区分享你的想法和经验,让我们一起交流学习!觉得有用请转发给更多同行,让更多开发者受益! 🚀
关注我,获取更多C#实战技巧和最佳实践!
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!