扩展方法的缺点?

时间:2008-11-23 05:57:36

标签: c# extension-methods

扩展方法是一个非常有用的功能,您可以在任何类中添加许多所需的功能。但我想知道是否有任何不利因素可能给我带来麻烦。有任何意见或建议吗?

7 个答案:

答案 0 :(得分:36)

  • 导入扩展方法的方式(即一次整个命名空间)并不精细。您无法从名称空间导入一个扩展名而无法完成所有其他扩展。
  • 从定义方法的源代码中不是很明显。这也是优势 - 这意味着您可以使代码看起来与该类型的其他方法一致,即使您无法出于某种原因将它放在同一个地方。换句话说,代码在高级别上更容易理解,但在<​​em>完全正在执行的内容方面更复杂。我也认为LINQ也是如此。
  • 您只能使用扩展方法,而不能使用属性,索引器,运算符,构造函数等。
  • 如果您正在扩展第三方课程,并且在更高版本中他们引入了具有相同签名的新方法,您将不会轻易知道您的调用代码的含义已经改变。如果新方法与你的扩展非常相似,但是边界条件略有不同(或其他),那么这可能会导致一些非常棘手的错误。但是相对来说不太可能发生。

答案 1 :(得分:4)

一些事情:

  • 除非你在VS.NET中,否则并不总是清楚扩展方法的来源。
  • 无法通过反射或C#4.0的动态查找来解析扩展方法

答案 2 :(得分:3)

扩展方法很有趣,但它们存在潜在问题。例如,如果您编写扩展方法而另一个库创建具有相同签名的扩展方法,该怎么办?您最终将难以使用这两个名称空间。

此外,可以说它们不易被发现。我认为这取决于这个。在某些情况下,您的代码应该包含在一个类中,在其他情况下,可以将该功能添加为扩展方法。

我通常将扩展方法作为我自己的类或BCL类的包装器,并将它们放在不同的名称空间中。例如Utils和Utils.Extensions。这样就不必使用extesions了。

答案 3 :(得分:2)

  • 使用静态方法进行的空值检查是不同的。不一定更好或更糟 - 但不同,开发人员需要了解这一点。能够在空值上调用方法可能是意外的,并且(有时)非常有用。

  • 没有多态(虽然支持重载)

  • 如果两种扩展方法与源类型冲突(并且都不符合“更好”),则可能会出现歧义。编译器然后拒绝使用...这意味着在程序集A中添加扩展方法可以破坏程序集B中的*无关代码。我已经看过几次......

  • 你不能在C#2.0中使用,所以如果你正在为C#2.0编写一个库它没有帮助

  • 它需要[ExtensionAttribute] - 所以如果你正在为.NET 2.0编写一个库,你会遇到一个问题:如果你声明你的拥有 [ExtensionAttribute],它可能会与.NET 3.5调用者

不要误解我的意思 - 我是个粉丝!

您可能猜到我正在编写一个需要为C#2.0和.NET 2.0调用者工作的库 - 而且(令人讨厌的)扩展方法真的非常有用!

* =仅适用于编译器;已编译的代码将没有问题

答案 4 :(得分:0)

就缺点而言,我会看到它们有点像宏 - 你最终可能会遇到难以维护的代码,因为其他人可能不熟悉你添加的扩展程序。

答案 5 :(得分:0)

我很难想象在不了解现有代码的情况下添加方法。例如,你一直在使用第三方类做某事,你需要扩展这个类的功能,因为你不是原始的开发人员,你不知道如何在类?做一件这样的事情几乎是没有意义的,就像你无法看到它时驾驶一样毫无意义。在由Microsoft设计人员/代码实现的LINQ的情况下,它很有意义,因为他们拥有如何说序列的实现内部的知识,现在他们希望通过添加Count方法来扩展其功能来计算所有序列中的元素。通过这样说,我希望通过提供一个需要扩展方法的现实例子,有人会认为我错了。

答案 6 :(得分:0)

在两种不同的情况下,扩展方法会起作用:

  1. 如果要扩展来自外部程序集的任何类,接口的结构,但未标记为密封的类除外,在这些类中,您可以选择从这些类派生并使用其他方法进行扩展,则可以仅,我仅重复此选项可用。密封的类和struct不能被继承,指向接口也要少提及。
  2. 但是,在您自己的程序集中,为特定的类,结构或接口提供扩展方法是一个非常主观的设计问题。如果您想对将使用装配体的人慷慨大方,则可以创建非常小的接口,理想情况下只需很少的属性,然后将整个扩展方法附加到它们上。这是示例:

    public interface IPointF{
        float X { get; }
        float Y { get; }
    }
    
    public struct PointF: IPointF{
        public PointF(float x, float y){
            X=x;Y=y;
        }
        public float X { get; private set; }
        public float Y { get; private set; }
    }
    
    public static class PointHelper{
        public static PointF ADD(this IPointF p, float val){
            return new PointF(p.x+val, p.y+val);
        }
    }
    

因此,任何未来的用户都可以通过继承IPoint来节省编码时间。