扩展方法 vs 静态工具类

46

我正在寻找在C#应用中使用扩展方法与静态工具类之间的优缺点。

例如,使用扩展方法的优点是通过类名方便调用,而不是像“StringUtils”这样。但缺点是它可能会模糊框架中存在的内容和不存在的内容之间的界限。


类似的问题已经发布在这里:https://dev59.com/sHRB5IYBdhLWcg3w3K0J 和这里:https://dev59.com/bkrSa4cB1Zd3GeqPTApn。 - HABJAN
可能是评估在C# => 3.0中使用扩展方法的成本/收益的重复问题。 - Hans Passant
3个回答

54

我觉得它的优点是模糊了框架内外的界限:你可以像使用框架代码一样自然地使用自己的代码,操作框架类型。

当然,不应该随意使用扩展方法 - 并不是所有的静态方法都应该成为扩展方法。

我试着考虑这个方法是否在逻辑上“对”它的第一个参数进行操作。如果您能将其包括为实例方法,那么它是否有意义呢?

可能你没有意识到的一个“缺点”:如果扩展类型后来添加了一个与相同参数适用的同名实例方法,那么在下一次重新编译时,你的调用代码将自动开始调用那个实例方法。例如,在 .NET 4 中,Stream 增加了CopyTo方法... 我之前写了一个 CopyTo 扩展方法,然后就无法被调用了。这发生时没有任何警告,所以你必须保持警惕。

一个警告:扩展方法还没有存在足够长的时间,以便真正建立最佳实践。你应该仔细权衡所有意见(甚至 - 或者也许特别是 - 我自己的意见)。


3
7年过去了,最佳实践是否已经确立? - Michael Haddad
8
不是特别的:) - Jon Skeet
1
@JonSkeet,你认为在枚举上使用扩展方法怎么样? - Fred
1
@Fred:如果有用的话,就去试试吧。 - Jon Skeet

13

归根结底,两种方法都使用静态方法。唯一的区别在于

string foo = "bob";
StringUtils.DoSomething(foo);

string foo = "bob";
foo.DoSomething();

是一种语法糖。它归结为个人喜好和编码标准。有时方法名可以足够描述,不需要看到静态类名。而其他情况下,则更合理包含类名。

最后,扩展方法也可以作为静态方法调用!

string foo = "bob";
StringExtensions.DoSomething(foo);

上面的代码与第二个示例中使用的代码相同,但调用方式不同。请记住这个小技巧,您可以创建静态实用程序类作为扩展方法,然后以任何希望的方式调用它们。


8
顺便提一下,语法不是唯一的区别。扩展方法不使用隐式转换,而静态方法则使用。例如,long myLong; IntExtension.DoSomething(myLong) 可以正常工作,但 myLong.DoSomething() 将无法编译通过。这是扩展方法的预期行为,但与常规静态方法不同。 - NOtherDev

6

我个人喜欢扩展方法提供的可读性和链式调用(隐式提供可读性)。

 1) Readability:  
     bool empty = String.IsNullOrEmpty (myString)
     //in comparison to
     bool empty = myString.IsNullOrEmpty ();

 2) Chain calls:  
    var query = Enumerable.Range(0, 10)
                         .Where(x => x % 2 == 0)
                         .Reverse();
    //instead of
    var query = Enumerable.Reverse(Enumerable.Where(Enumerable.Range(0, 10), x => x % 2 == 0));

如果您不小心这样做,您的扩展方法可能会被实例成员覆盖。个人而言,我不喜欢这种情况发生。至少编译器应该会警告,在同一程序集中发生此类情况时。


为什么在选项1中你要在括号前留空格? - Ed_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接