C#.NET 14 扩展成员(Extension Members) 让半成品扩展方法进入完整形态
C# 14 扩展成员(Extension Members)
扩展方法始终是半成品
我从不讨厌扩展方法。它们很有用。但说实话,它们总是让人觉得语言在说:
"嘿,我们知道你想在不修改源码的情况下扩展API,所以这里有一个伪装成更酷东西的静态方法。别看得太仔细。"
而你确实仔细看了,不是吗?
- 不能添加属性
- 不能添加运算符
- 除了笨拙的静态类之外,无法对相关扩展进行逻辑分组
- 它们从未真正感觉像是类型的一部分
现在有了扩展成员——这是扩展方法一直想要成为的成熟版本。
示例1:经典的ToObservable重写
如果你使用过MVVM模式(WPF、Xamarin、MAUI等),可能已经写过上百次这样的代码:
public static class ObservableExtensions
{
public static ObservableCollection<T> ToObservable<T>(this IEnumerable<T> source)
=> new ObservableCollection<T>(source);
}
它能用,但感觉很别扭;它不像是对现有类型的扩展。现在来看看扩展成员的方式:
public static class EnumerableExtensions
{
extension(IEnumerable<T> collection)
{
public ObservableCollection<T> ToObservable()
=> new ObservableCollection<T>(collection);
}
}
看到区别了吗?没有杂乱代码。没有奇怪的"静态方法假装成真实成员"。感觉就像IEnumerable<T>本身就拥有这个行为。如果你在职业生涯中使用过Swift,可能会对这个功能深有感触,我理解,这简直是🤌(完美)
语法速览:扩展成员一览
如果你想掌握这个语法:
public static class NameOfExtensionClass
{
extension(YourType obj)
{
// 方法、属性、运算符,甚至嵌套类型
}
}
是的,你没看错,允许使用属性和运算符。
示例2:添加真正有意义的属性
是否曾想要一种简洁的方法来检查集合是否为空,而不必到处写!collection.Any()或collection.Count == 0?
使用扩展成员:
public static class CollectionExtensions
{
extension(ICollection<T> collection)
{
public bool IsEmpty => this.Count == 0;
}
}
用法:
if (myList.IsEmpty)
{
// 终于以应有的方式阅读代码了
}
这是扩展方法永远无法优雅实现的事情;现在它感觉像是类型系统的自然组成部分。
示例3:静态扩展成员
你甚至可以向不拥有的类型添加静态成员:
public static class DateTimeExtensions
{
extension(DateTime)
{
public static DateTime UnixEpoch => new DateTime(1970, 1, 1);
}
}
迁移现有代码
有一整个静态扩展方法库?可以这样迁移:
之前:
public static class DateTimeExtensions
{
public static bool IsWeekend(this DateTime date)
=> date.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday;
}
之后:
public static class DateTimeExtensions
{
extension(DateTime dateTime)
{
public bool IsWeekend => dateTime.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday;
}
}
更简洁。更易发现。更易维护。
底层工作原理
对于好奇的读者,这里简单说明:
- 它们不修改原始类型
- 编译器和元数据将它们视为"附加"成员
- 工具(如IntelliSense)将它们显示为好像属于该类型
- 底层仍然是安全且分离的,只是更智能
想让我深入探讨机制吗?在评论区留言,我可能会专门写一篇文章。
需要了解的局限性
它们是新功能,所以:
- 没有运行时魔法,仅编译时有效
- 不能添加字段或操作私有成员
- 现代IDE之外的工具可能暂时支持滞后
但说实话?相对于我们获得的功能,这些都是次要的权衡。
为什么这是我最喜欢的功能
扩展成员终于让扩展感觉像是一等公民。它们让API自然演进。它们减少了代码杂乱。它们让代码读起来就像原本就是这样设计的。
这不仅仅是语法糖。这是让我对重构旧代码库感到兴奋的功能——我不常这么说。
扩展成员不仅仅是一个闪亮的新语法。它们是一次课程修正。它们完成了扩展方法开始的工作。更简洁的API、可发现的功能、隐藏在随机命名空间中的工具类更少,这一切都感觉……恰到好处。
这就是为什么这是我最喜欢的C# 14功能。它不会让你重新思考如何编写部分代码,而是让你重新思考如何设计所有代码。