如何在Visual Studio C#中将常见/相似的代码块提取为函数

4

我想选择代码,例如:

doSomething(myEnum.firstThing)
doSomethingElse(myEnum.firstThing)
evenMoreStuff(myEnum.firstThing)

将其转换为函数
GroupCommonStuf(myEnum.firstThing)

这将会看起来像:

GroupCommonStuff(myEnum id)
{
  doSomething(id)
  doSomethingElse(id)
  evenMoreStuff(id)
}

最好能够捕捉到任何以下代码:

doSomething(myEnum.secondThing)
doSomethingElse(myEnum.secondThing)
evenMoreStuff(myEnum.secondThing)

并将其转换为
GroupCommonStuf(myEnum.secondThing)

我安装了ReSharper。但是在ReSharper中提取方法似乎只会提取我选择的代码块,它不会将其传播到其他“相似的代码”,我确信Eclipse可以为C++和Java做到这一点。

我想我也可以通过正则表达式来实现这一点,但我还没有掌握正则表达式。我该怎么做?


很好的想法。除非你只是处理函数,否则我无法想象这将如何在不解析代码的情况下工作 - 即使是这样,我也能看到一些陷阱。 一旦创建了语法树 - 也许你可以用某种最小阈值的扩展搜索来完成。在我的脑海中,我正在设计一个编译器 - 所以祝你好运。;-) - Daniel Gimenez
除非我是戴着玫瑰色眼镜回忆,否则我敢发誓在Eclipse中这是可能的...我想我可以写一个解析器...很诱人 :p - chrispepper1989
感谢“搜索模式”解析器,不需要使用解析器 :) 也许可以通过利用以下链接将下面的3个步骤合并为一个步骤: https://www.jetbrains.com/resharper/features/open_api.html - chrispepper1989
1个回答

4

使用三个有用的ReSharper工具,可以通过以下三个步骤实现:

  • 提取到方法
  • 引入参数
  • 使用模式搜索

没有ReSharper的可能替代方案在底部


  1. Select one offending code block, Extract To Method

    (Ctrl + R, M)*** or right clickRefactorExtractMethod)

    Result:

    GroupCommonStuf()
    {
        doSomething(myEnum.firstThing)
        doSomethingElse(myEnum.firstThing)
        evenMoreStuff(myEnum.firstThing)
    
    }
    
  2. Select one "myEnum.firstThing" within the function, Introduce Parameter (Ctrl + R, P) or right clickRefactorIntroduce parameter

    The wizard is pretty self explanatory :)

    Result:

    GroupCommonStuf(myEnum type)
    {
        doSomething(type)
        doSomethingElse(type)
        evenMoreStuff(type)
    }
    
  3. ReSharper → FindSearch With Pattern (click replace tab)

    OR Select an untouched offending code block, Right click* → Find Similar Code

  4. Click Add PlaceHolder→ "Type" = Arguments → "Name"=enumeration

  5. Type the following:

    Enter image description here

    Result:

    Using the above pattern script code blocks that match:

    doSomething(myEnum.firstThing);
    doSomethingElse(myEnum.firstThing);
    evenMoreStuff(myEnum.firstThing);
    

    will be replaced with

    GroupCommonStuf(myEnum.firstThing)
    

    The same for any variation of the enum :).

关于这里发生的事情的一些解释

简而言之,ReSharper正在查找()之间的任何参数,并将它们存储在“枚举”变量中(名称实际上并不重要)。然后,在替换块中出现该变量的任何位置插入这个参数字符串。

有不同的占位符可以执行不同的操作,使用正确的占位符非常重要。 "type"占位符甚至支持正则表达式,使其非常强大。

在这种情况下,你可以简单地输入$enumeration$,因为默认占位符是 "arguments"。但是,我建议养成使用 "add placeholder" 的习惯,因为当你处理更复杂的模式时,它会更清晰。重要的是要知道它不仅仅是“将字符串放入变量中”。

为了更好地解释这一点,请考虑以下示例,假设你在代码中随处可见:

... = GetGraphic(Graphics.First).ShapeArray[index].ShapeColour
... = GetGraphic(Graphics.Second).ShapeArray[index].ShapeSize
... = GetGraphic(Graphics.First).ShapeArray[index].ShapeSize

你已决定用更相似的代码替换所有这些内容

... = GetShapeColour(Graphics.First, index);
... = GetShapeSize(Graphics.Second, index);
... = GetShapeSize(Graphics.First, index);

通过使用正确的占位符,您可以通过一次搜索和替换来完成此操作:

enter image description here

  • $args$(一个参数占位符)负责为您处理参数,本例中只有一个参数,但也可以有多个。
  • $variableOfArray$(一种类型占位符,带有正则表达式Shape*)负责移动ShapeColour、ShapeSize“变量类型”名称。

如果您使用“参数占位符”来代替“variableOfArray”,Resharper会提示找不到该模式的任何出现,因为根本不存在 GetGraphic( .. ).ShapeArray[index].( .. )。


没有 ReSharper 的可能解决方案:

提取到方法 → 提取方法重构

引入参数 → 使用/不使用“查找替换”升级变量为参数

使用模式搜索 → 对我来说,这显然是最难的一个,有三个选项我不想特别探索,我猜通常需要比手动更改花费更多的时间:

  • 非常聪明的正则表达式(这可能在 Visual Studio 内部很烦人)
  • 带有巧妙 sed 的 Bash 脚本(比仅在 Visual Studio 中使用 regexing 稍微好一些,但仍然很难)
  • 编写自己的解析器???当所有其他方法都失败时......看代码!

2
+1,但我会使用“引入参数”而不是搜索和替换。 - John Saunders
@JohnSaunders,太酷了,我不知道这个(我是Resharper的新手),我会改进我的答案。 - chrispepper1989

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