在C#(或任何语言)中,您最喜欢的去除重复的方法是什么?

4
我刚编写了一个700行的类。太糟糕了。我感到惭愧。这与DRY截然相反,就像英国的夏天一样。
它充满了复制和粘贴,只是在这里和那里进行了微小的调整。这使得它成为重构的首选对象。在开始之前,我想问一下,当你有很多重复的代码时,你首先寻找哪些重构机会?
记录一下,我的可能是使用:
  1. 通用类和方法
  2. 方法重载/链接。
你的呢?

如果仍有人在阅读这个问题,我已经将我的类减少了一半。我使用TDD重新编写了它。还有一些重构工作要做。自己注意:即使是原型设计也一定要使用TDD。 - Iain Holder
7个回答

4

我喜欢在需要重构时开始工作,而不是第一次有机会就开始。你可以说这是一种敏捷的重构方法。我何时感觉需要呢?通常是当我感觉我的代码中的丑陋部分开始蔓延时。我认为只要它们被包含在内,丑陋是可以接受的,但当它们开始有扩散的冲动时,那就是你需要处理的时候了。

重构时使用的技术应该从最简单的开始。我强烈推荐马丁·福勒的书。将通用代码组合成函数、删除不必要的变量和其他简单技巧可以让你获得很多收益。对于列表操作,我更喜欢使用函数式编程习惯。也就是说,我尽可能地使用内部迭代器、map、filter和reduce(在Python中有相应的东西,在Ruby、Lisp和Haskell中也有),这样可以使代码更加简洁和自包含。


是的,Fowler的书真的很好。也许我应该更经常地翻阅它! :) - Iain Holder

2

#region

我使用了一个1,000 行代码的类,但只用到了其中一行!

说真的,避免重复的最好方法是按照你的列表中所涵盖的事项,并充分利用多态性,检查你的类并发现在基类中应该进行的最佳操作以及如何将其不同部分分解为子类。


1
#region:这是一个可以隐藏你的不可告人秘密的地方。 - thijs

2
有时候,当你使用复制和粘贴的代码完成功能时,你已经到了一个程度,它已经被破坏得足够严重,任何尝试重构的努力实际上都要比在明显的点上重构花费更长的时间。
在我个人的经验中,我最喜欢的“消除重复”的方法是Resharper的“提取方法”功能(虽然这也可以在原始的Visual Studio中使用)。
很多时候,我会看到重复的代码(一些我正在维护的旧应用程序),不是整个方法,而是在完全不同的方法中的块。这给了我们一个完美的机会将这些块转换为方法。
庞大的类也往往会显示它们包含多个功能。这反过来又成为将每个不同的功能分离到自己的(希望更小的)类中的机会。
我必须重申,做所有这些对我来说并不是一件愉快的事情,所以我真的宁愿在它是一个小泥球的时候就把它做好,而不是让大泥球滚动,然后试图修复它。

1

首先,我建议在第一个类版本完成之前尽早进行重构。每当发现代码重复时,立即消除它。虽然这可能会花费一些额外的时间,但我认为结果会更加干净,并且在您编写代码时有助于重新思考以确保正确执行。

至于我最喜欢消除重复的方法...闭包,特别是在我最喜欢的语言(Ruby)中。它们往往是将两个代码片段合并相似性的一种非常简洁的方式。当然(像任何“最佳实践”或技巧一样),这不能盲目地完成...但我发现当我能使用它们时,它们非常有趣。


你说得很对,不要等到课程结束。我被完成功能的冲动所超越。 - Iain Holder

1
我做的一件事情是尝试制作小而简单的方法,这样我就可以在编辑器(Visual Studio)的单个页面上看到它们。
从经验中我学到,让代码简单化可以使编译器更容易地对其进行优化。方法越大,编译器的工作就越难!
最近我还遇到了一个问题,即大型方法导致内存泄漏。基本上,我有一个循环,非常类似于以下内容:
while (true) { var smallObject = WaitForSomethingToTurnUp(); var largeObject = DoSomethingWithSmallObject(); }
我发现我的应用程序会保留大量数据在内存中,因为即使“largeObject”直到smallObject返回某些东西才出现,垃圾收集器仍然可以看到它。
我通过将“DoSomethingWithSmallObject()”和其他相关代码移动到另一个方法中轻松解决了这个问题。
此外,如果您制作小方法,则在类内重复使用的可能性将显着提高。我通常会确保我的所有方法都不像其他任何方法!
希望这可以帮助您。
Nick

1
“剪切和粘贴,稍加修改”是我通常用非常规方法解决的代码重复问题——将相似的代码块提取出来,放到一个单独的方法中。每个代码块实例中不同的一点,可以通过参数进行修改。
此外,Scott Hanselman提供了一些简单的技巧,可以消除看起来重复的if/else if和switch块: http://www.hanselman.com/blog/CategoryView.aspx?category=Source+Code&page=2

1

我可能会这样做:

为数据结构创建自定义(私有)类型,并将所有相关逻辑放在其中。例如:Dictionary<string, List<int>>等。

创建内部函数或属性以保证行为。如果您不断地从公共可访问的属性检查条件,则创建一个带有所有检查内容的私有getter方法。

将具有过多操作的方法拆分开来。如果您无法将某些简洁的东西放入函数中或给它一个好的名称,那么请开始将该函数拆分,直到代码变得简单易懂(即使这些“子”函数在其他地方没有使用)。

如果一切都失败了,请在其上打上[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]并注释原因。


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