从此

🏠 » 📄文章 » 内容

 欢迎来访!

C#.NET 14 扩展成员(Extension Members) 让半成品扩展方法进入完整形态

🕗2026-02-18👁️0

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功能。它不会让你重新思考如何编写部分代码,而是让你重新思考如何设计所有代码。