扩展方法与继承

时间:2009-07-15 15:48:51

标签: c# .net class extension-methods

是否有经验法则有助于确定在哪种情况下使用哪个?我大多数时候比较喜欢一个吗?

谢谢!

9 个答案:

答案 0 :(得分:31)

扩展方法很有用,但它们通过IDE比常规方法更难发现,因为它们没有附加到原始类,也没有关于它们的代码可能驻留在何处的线索。有一些best practice suggestions关于在何处放置它们以及如何命名它们,但这些只是指导原则,并且无法保证有人会遵循它们。

如果您只是为一个众所周知的,使用良好的类或接口(例如.Net基类)添加功能而无法访问代码,那么通常会使用扩展方法。扩展方法也有一个限制,因为你不仅需要拥有原始程序集,还必须在其中包含扩展方法的程序集,这必须由代码的使用者理解。

使用继承将允许您添加,删除或覆盖功能,并确保在构建时它始终与类一起出现。

答案 1 :(得分:14)

当您希望提供应该共享相同行为的各种类型的实现时,应该使用扩展方法,否则将不同。这就是为什么你看到很多接口上使用扩展方法的原因,因为它是一个非常强大的工具,可以确保接口的任何给定实现都具有给定行为的相同实现。

例如,Skip and Take扩展方法。

答案 2 :(得分:8)

尽可能使用继承而不是扩展方法

修改

我更喜欢保持简短,但我当然会回答后续问题。

在可以继承的情况下,也就是说没有密封的类,它几乎总是比扩展方法更好的选择。实际上,这就是所引用的best practices document所说的内容。它有标题,如“警惕扩展方法”,“在扩展你不拥有的类型之前三思而后行”,以及“首选扩展类扩展的接口扩展”。换句话说,它只是更详细地说出了我的单行所做的事情。

本文确实给出了详细的原因,但最重要的是,这就是设计使用扩展方法的方式。他们在游戏后期被添加到语言中作为一些语法糖,以允许MS楔入LINQ而无需返回并重新发明轮子。这是他们有益的典型例子。另一个很好的例子是添加实用程序方法,例如:

public static string FormatWith(this string format, params object[] args)
{ return string.Format(CultureInfo.InvariantCulture, format, args); }

请注意,在这种情况下,扩展方法是实现此附加功能的唯一方法,因为字符串是密封的。

关于继承的构成,虽然这是一个老生常谈,但我没有看到这里的相关性。无论我们是使用扩展方法还是继承,目标都是更改接口以允许其他方法。无论是通过组合,泛型还是其他技术,这种方法的实现方式都是正交的。

答案 3 :(得分:8)

嗯......你不能总是使用继承。例如,String是一个密封的类。在那些扩展方法确实闪耀的情况下。

通常,扩展方法最适用于您可能放入静态类但对特定类型的实例进行操作的小实用程序。字符串是一个很好的例子 - 几乎每个人都有自己的小字符串扩展方法来对字符串进行少量操作。

扩展方法的另一个好处是反对枚举。我几乎总是在我创建的任何HasFlag枚举中包含[Flags]扩展方法。

答案 4 :(得分:2)

它们是非常不同的,例如LINQ标准查询运算符是扩展方法的一个很好的例子,应该很难通过继承来实现,但是如果你有权访问类并且可以更改源代码,那么最好使用继承,
编辑
以下是我在这里找到的一些规则C# 3.0 Features: Extension Methods

  • 扩展方法不能用于覆盖现有方法
  • 不会调用与实例方法具有相同名称和签名的扩展方法
  • 扩展方法的概念不能应用于字段,属性或事件
  • 谨慎使用扩展方法....过度使用可能是一件坏事!

答案 5 :(得分:2)

除了扩展方法主要用于扩展密封类或创建特定于范围的扩展的情况之外,我会坚持继承。还要记住它们是静态的,所以如果这些是你需要在其他类中重写的方法和行为,你就不能真正使用扩展。

扩展方法确实有一个非常棒的功能,这是它们实现的固有优势。由于它们是静态方法,因此可以在null对象上调用它们。

例如:

string a = null;
return a.IfNullOrEmpty("Default Value");

这样的实现很棒,虽然它们在技术上只是语法糖。恕我直言,任何能让你的代码更清晰,更易读的东西都很棒。

虽然我不喜欢它,但它们并不是真的可以被发现。如果我将该代码从一个类复制到另一个类,那么我将不得不搜索定义它的命名空间。

答案 6 :(得分:0)

这实际上取决于你需要解决的问题,在大多数情况下,类继承和接口自然比扩展方法更有意义,因此应该是首选。

另一方面,扩展程序允许您创建有用的方法,将应用于一个类 - 这对于继承来说会更麻烦/ strong>,如果不是几乎不可能实现的话。

以下是一些使用扩展方法的例子:


LinqPad使用扩展方法,例如.Dump()方法,您可以使用该方法将每种对象的内容转储(打印)到输出窗口。


.NET framework 本身在很多地方使用扩展方法,例如Linq:

public static TSource FirstOrDefault<TSource>(this 
                        System.Collections.Generic.IEnumerable<TSource> source)

返回任何对象类型的任何可枚举集合的第一个元素或默认值。


扩展方法优于继承的示例如下: 假设您要创建一种能够创建任何现有对象的clone(复制)的方法。使用扩展程序(以及泛型,加上反射),您可以执行此操作this way

答案 7 :(得分:0)

MSDN

C# programming guide中有关扩展方法的页面中,内容为:

一般准则

通常,我们建议您仅在必要时谨慎地实施扩展方法。只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来进行扩展。有关更多信息,请参见继承(C#编程指南)。

在使用扩展方法扩展无法更改其源代码的类型时,存在这样的风险,即类型实现的更改将导致扩展方法中断。

答案 8 :(得分:-1)

扩展方法打破了良好的OO设计。要说它们应该用在你无法访问代码库的密封类上是荒谬的。密封且您无法访问的类可能因某种原因(性能,线程安全性)而被密封,并且盲目地将这些类标记为功能是非常危险的。始终有一种以纯OO方式实现装饰器模式的方法,并且不这样做会使代码更难以读取,维护和重构。根据经验,如果某种语言的特征闻起来不好,那就应该避免。我相信你可以找到一个扩展方法有用的例子,但事实是,那些开发人员只需要进行最少的OO培训就会滥用该功能。