扩展方法Extension Methods

扩展方法是一种语言特性,允许使用实例方法调用语法来调用静态方法。Extension methods are a language feature that allows static methods to be called using instance method call syntax. 这些方法必须至少使用一个参数,该参数表示方法要操作的实例。These methods must take at least one parameter, which represents the instance the method is to operate on.

定义此类扩展方法的类称“sponsor”类,必须将其声明为静态。The class that defines such extension methods is referred to as the "sponsor" class, and it must be declared as static. 要使用扩展方法,必须导入定义 sponsor 类的命名空间。To use extension methods, one must import the namespace defining the sponsor class.

❌ 避免 frivolously 定义扩展方法,特别是对于不属于您的类型。❌ AVOID frivolously defining extension methods, especially on types you don’t own.

如果拥有某一类型的源代码,请考虑使用常规实例方法。If you do own source code of a type, consider using regular instance methods instead. 如果没有,并且想要添加方法,请务必小心。If you don’t own, and you want to add a method, be very careful. 随意使用扩展方法可能会使本来不具备这些方法的类型产生混乱的API。Liberal use of extension methods has the potential of cluttering APIs of types that were not designed to have these methods.

✔️考虑在以下任何情况下使用扩展方法:✔️ CONSIDER using extension methods in any of the following scenarios:

  • 提供与接口的每个实现相关的辅助功能(如果上述功能可以根据核心接口编写)。To provide helper functionality relevant to every implementation of an interface, if said functionality can be written in terms of the core interface. 这是因为不能将具体实现分配给接口。This is because concrete implementations cannot otherwise be assigned to interfaces. 例如,LINQ to Objects 运算符作为所有 IEnumerable<T> 类型的扩展方法实现。For example, the LINQ to Objects operators are implemented as extension methods for all IEnumerable<T> types. 因此,任何 IEnumerable<> 实现都会自动启用 LINQ。Thus, any IEnumerable<> implementation is automatically LINQ-enabled.

  • 当实例方法在某种类型上引入依赖关系,但这样的依赖关系会破坏依赖关系管理规则的时候。When an instance method would introduce a dependency on some type, but such a dependency would break dependency management rules. 例如,从 StringSystem.Uri 的依赖关系可能并不理想,因此,从依赖关系管理的角度来看,返回 System.UriString.ToUri() 实例方法将是错误的设计。For example, a dependency from String to System.Uri is probably not desirable, and so String.ToUri() instance method returning System.Uri would be the wrong design from a dependency management perspective. 静态扩展方法 Uri.ToUri(this string str) 返回 System.Uri 将是更好的设计。A static extension method Uri.ToUri(this string str) returning System.Uri would be a much better design.

❌ 避免在 System.Object上定义扩展方法。❌ AVOID defining extension methods on System.Object.

Visual Basic 用户将无法使用扩展方法语法对对象引用调用此类方法。Visual Basic users will not be able to call such methods on object references using the extension method syntax. Visual Basic 不支持调用此类方法,因为在 Visual Basic 中,将引用声明为对象将强制其上的所有方法调用都是后期绑定的(在运行时确定调用的实际成员),而扩展方法的绑定则在编译时(早期绑定)。Visual Basic does not support calling such methods because, in Visual Basic, declaring a reference as Object forces all method invocations on it to be late bound (actual member called is determined at runtime), while bindings to extension methods are determined at compile-time (early bound).

请注意,该准则适用于存在相同绑定行为的其他语言,或者不支持扩展方法的其他语言。Note that the guideline applies to other languages where the same binding behavior is present, or where extension methods are not supported.

❌ 不要将扩展方法放在与扩展类型相同的命名空间中,除非它用于向接口添加方法或用于依赖项管理。❌ DO NOT put extension methods in the same namespace as the extended type unless it is for adding methods to interfaces or for dependency management.

❌ 避免定义具有相同签名的两个或多个扩展方法,即使它们驻留在不同的命名空间中。❌ AVOID defining two or more extension methods with the same signature, even if they reside in different namespaces.

如果类型是一个接口,则✔️考虑在与扩展类型相同的命名空间中定义扩展方法,并且在大多数或所有情况下都使用扩展方法。✔️ CONSIDER defining extension methods in the same namespace as the extended type if the type is an interface and if the extension methods are meant to be used in most or all cases.

❌ 不会定义实现通常与其他功能关联的命名空间中的功能的扩展方法。❌ DO NOT define extension methods implementing a feature in namespaces normally associated with other features. 而是在与它们所属的功能相关联的命名空间中定义它们。Instead, define them in the namespace associated with the feature they belong to.

❌ 避免命名空间专用于扩展方法(例如 "Extension")的命名空间。❌ AVOID generic naming of namespaces dedicated to extension methods (e.g., "Extensions"). 而是使用描述性名称(例如,“路由”)。Use a descriptive name (e.g., "Routing") instead.

部分©2005,2009 Microsoft Corporation。保留所有权利。Portions © 2005, 2009 Microsoft Corporation. All rights reserved.

*在 Pearson Education, Inc. 授权下,由 Addison-Wesley Professional 作为 Microsoft Windows 开发系列的一部分再版自 Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition(Framework 设计准则:可重用 .NET 库的约定、惯例和模式第 2 版),由 Krzysztof Cwalina 和 Brad Abrams 发布于 2008 年 10 月 22 日。Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, published Oct 22, 2008 by Addison-Wesley Professional as part of the Microsoft Windows Development Series.

另请参阅See also