C# 扩展方法与继承

C# 扩展方法与继承,c#,.net,class,inheritance,extension-methods,C#,.net,Class,Inheritance,Extension Methods,是否有经验法则可以帮助确定在什么情况下使用哪种方法?大多数时候我应该更喜欢其中一个吗 谢谢 尽可能使用继承方法而不是扩展方法 编辑 我倾向于保持简短,但我当然会回答后续问题 在继承是可能的情况下,也就是说,没有密封的类,它几乎总是比扩展方法更好的选择。事实上,这就是womp引用的文件所说的。它的标题有“警惕扩展方法”、“在扩展不属于自己的类型之前三思而后行”和“更喜欢接口扩展而不是类扩展”。换句话说,它只是更详细地说明了我的一行代码所做的事情 本文确实给出了详细的原因,但底线是扩展方法就是这样设

是否有经验法则可以帮助确定在什么情况下使用哪种方法?大多数时候我应该更喜欢其中一个吗


谢谢

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

编辑

我倾向于保持简短,但我当然会回答后续问题

在继承是可能的情况下,也就是说,没有密封的类,它几乎总是比扩展方法更好的选择。事实上,这就是womp引用的文件所说的。它的标题有“警惕扩展方法”、“在扩展不属于自己的类型之前三思而后行”和“更喜欢接口扩展而不是类扩展”。换句话说,它只是更详细地说明了我的一行代码所做的事情

本文确实给出了详细的原因,但底线是扩展方法就是这样设计的。在游戏后期,它们被添加到语言中,作为一点语法糖分,以允许MS插入LINQ,而不必回去重新发明轮子。这是它们的好处的典型例子。另一个很好的例子是添加实用程序方法,例如:

public static string FormatWith(this string format, params object[] args)
{ return string.Format(CultureInfo.InvariantCulture, format, args); }
请注意,在本例中,扩展方法是实现此附加功能的唯一方法,因为字符串是密封的


至于构图而非继承,虽然这是一个真理,但我看不出这里的相关性。无论我们使用的是扩展方法还是继承方法,目标都是更改接口以允许使用其他方法。该方法的实现方式,无论是通过组合、泛型还是其他技术,都是正交的。

它们非常不同,例如LINQ标准查询运算符是扩展方法的一个很好的例子,很难通过继承实现,但如果您有权访问类并可以更改源代码,则最好使用继承,
编辑

,下面是我在这里找到的一些规则

  • 扩展方法不能用于重写现有方法
  • 将不会调用与实例方法具有相同名称和签名的扩展方法
  • 扩展方法的概念不能应用于字段、属性或事件
  • 谨慎使用扩展方法……过度使用可能是一件坏事
当您希望跨多种类型提供一个实现时,应该使用扩展方法,这些实现应该共享相同的行为,但在其他方面可能不相似。这就是为什么在接口上经常使用扩展方法的原因,因为它是一个非常强大的工具,可以确保接口的任何给定实现都具有给定行为的相同实现


例如,Skip和Take扩展方法。

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

通常,如果您只是将功能添加到一个众所周知、使用广泛的类或接口(如.Net基类),而您无权访问该类或接口的代码,那么您会使用扩展方法。扩展方法还有一个约束,即您不仅必须拥有原始程序集,还必须拥有包含扩展方法的程序集,这必须被代码的使用者理解

使用继承将允许您添加、删除或重写功能,并确保在构建类时它始终存在于类中。

好吧。。。不能总是使用继承<例如,code>String是一个密封类。在这种情况下,扩展方法才是真正的亮点

一般来说,扩展方法最适合于小实用程序,这些小实用程序可以放在静态类中,但可以针对特定类型的实例进行操作。字符串就是一个很好的例子——几乎每个人都有自己的小字符串扩展方法来对字符串执行小操作


扩展方法的另一个好地方是反对枚举。对于我创建的任何
[Flags]
枚举,我几乎总是包含一个
hassflag
扩展方法

除非扩展方法主要是为扩展密封类或创建特定于范围的扩展而设计的,否则我将坚持继承。还要记住,它们是静态的,所以如果这些方法和行为需要在其他类中重写,那么就不能真正使用扩展

扩展方法确实有一个非常好的特性,这是它们实现的固有好处。因为它们是静态方法,所以可以在null对象上调用它们

例如:

string a = null;
return a.IfNullOrEmpty("Default Value");
像这样的实现非常好,尽管它们在技术上只是语法上的糖分。我知道,任何能让你的代码更干净、更可读的东西都是很棒的


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

扩展方法破坏了良好的OO设计。说它们应该用在你无法访问代码库的密封类上是荒谬的。被密封但您无权访问的类可能出于某种原因(性能、线程安全)而被密封,盲目地将功能标记到这些类是非常危险的。总有一种方法可以用纯面向对象的方式实现decorator模式,而不这样做会使代码更难阅读、维护和重构。根据经验,如果一种语言的某个特征闻起来很难闻,那么就应该避免它。我相信你可以找到一个例子,其中扩展方法是有用的,但事实是,该功能将是ab
public static TSource FirstOrDefault<TSource>(this 
                        System.Collections.Generic.IEnumerable<TSource> source)