扩展方法

注释

此内容由 Pearson Education, Inc. 的许可从 框架设计指南:可重用 .NET 库的约定、习惯和模式(第 2 版)重新打印。 该版于2008年出版,此后该书已于 第三版全面修订。 此页上的一些信息可能已过期。

扩展方法是一种语言功能,允许使用实例方法调用语法调用静态方法。 这些方法必须至少采用一个参数,该参数表示该方法要对其运行的实例。

定义此类扩展方法的类称为“发起人”类,必须将其声明为静态类。 若要使用扩展方法,必须导入定义发起方类的命名空间。

❌ 避免轻率地定义扩展方法,尤其是在你不拥有的类型上。

如果确实拥有类型的源代码,请考虑改用常规实例方法。 如果你没有所有权,但你想添加一种方法,请务必小心。 滥用扩展方法可能使那些原本并未设计为包含这些方法的类型API变得杂乱无章。

✔️ 请考虑在以下任一方案中使用扩展方法:

  • 为了提供与每个接口实现相关的辅助功能,条件是这些功能能够在核心接口的基础上编写。 这是因为具体实现不能直接分配给接口。 例如, LINQ to Objects 运算符作为所有类型的 IEnumerable<T> 扩展方法实现。 因此,任何 IEnumerable<> 实现都自动启用 LINQ。

  • 当实例方法会引入对某种类型的依赖,但这种依赖会破坏依赖管理规则时。 例如,从 StringSystem.Uri 的依赖可能是不需要的,因此,从依赖管理的角度来看,String.ToUri() 实例方法返回 System.Uri 将是错误的设计。 一个返回Uri.ToUri(this string str)的静态扩展方法System.Uri会是更好的设计。

❌ 避免在 System.Object 上定义扩展方法。

VB 用户无法使用扩展方法语法对对象引用调用此类方法。 VB 不支持调用此类方法,因为在 VB 中,将引用声明为 Object 会强制其上的所有方法调用延迟绑定(实际调用的成员在运行时确定),同时在编译时(早期绑定)确定对扩展方法的绑定。

请注意,该准则适用于存在相同绑定行为的其他语言,或者不支持扩展方法。

❌ 请勿将扩展方法放在与扩展类型的同一命名空间中,除非将方法添加到接口或依赖项管理。

❌ 避免使用同一签名定义两个或多个扩展方法,即使它们驻留在不同的命名空间中也是如此。

✔️ 如果类型是接口,并且扩展方法用于大多数或全部情况,请考虑在与扩展类型相同的命名空间中定义扩展方法。

❌ 请勿定义在通常与其他功能关联的命名空间中实现功能的扩展方法。 而是在与其所属的功能关联的命名空间中定义它们。

❌ 避免专用于扩展方法的命名空间的泛型命名(例如,“扩展”)。 请改用描述性名称(例如“路由”)。

部分内容 © 2005, 2009 Microsoft 公司。 保留所有权利。

经皮尔逊教育有限公司许可,从由 Krzysztof Cwalina 和 Brad Abrams 撰写的《框架设计准则:可重用 .NET 库的约定、习惯和模式》一书中重新印刷。此书由 Addison-Wesley Professional 于 2008 年 10 月 22 日出版,是微软 Windows 开发系列的一部分。

另请参阅