问题 远离主要构造者


Visual Studio 2013的C#6预览版支持主要构造函数,该团队已决定不会将其纳入最终版本。不幸的是,我的团队使用主要构造函数实现了200多个类。

我们现在正在寻找最简单的迁移源代码的途径。由于这是一次性的事情,一个神奇的正则表达式替换字符串或hacky解析器将起作用。

在我花大量时间写这样一只野兽之前,那里有没有人已经做过这个或知道更好的方法?


9209
2017-12-12 18:29


起源

你能告诉我们一个例子,以便我们得到一个更好的主意。 - ja72
有点疯狂的想法:在该预览中使用Roslyn的版本来执行代码重写。基本上,添加对随预览一起安装的Roslyn DLL的引用,并要求它构建您的解决方案。然后,对于每个编译,在语法树中搜索主构造函数节点,并相应地修改语法树。如果你在初始化器中使用参数,它可能会有点毛茸茸,请注意。我会认真地考虑手工操作 - 虽然单调乏味,但从长远来看它可能会更快。 - Jon Skeet
200听起来不是一个大数字。你的团队中有多少人?如果他们在您发布此问题时开始转换代码,那么现在他们已经完成了。 - Sriram Sakthivel
很抱歉说明显了,但你知道你不应该使用预发布软件来编写生产代码,对吧? - Gigi
@Gigi在我看来,这样一条全面的说明性声明在StackOverflow上并没有真正的位置。如果我们预先发布会怎么样?更不用说,我们开始睁大眼睛使用编译器并了解潜在的风险。对潜在风险发表评论将是一回事,但你不是在我或我的团队中,你不可能知道是什么原因导致我们在发布之前决定使用编译器。 - David Pfeffer


答案:


正如我在评论中建议的那样,你可以使用Roslyn的版本  了解主构造函数将代码解析为语法树,然后修改该语法树以使用“普通”构造函数。您还需要将使用主构造函数参数的所有初始化程序放入新构造函数中。

我怀疑编写该代码需要  至少两三个小时,可能更多 - 而我可以在相同的时间内手动完成相当多的课程。自动化很棒,但有时最快的解决方案就是手工完成......即使是200个类也可以更快地手动完成,你可以做到 无疑 将工作并行化为多人。


6
2018-01-23 16:35





(\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?\})(\s*?=\s*?\w*;\s*)
\1\2\4\5

一些答案:第一个用简单的正则表达式找到并替换你需要重复几次:

  1. 正则表达式:几行解释然后是实际的正则表达式字符串和替换字符串:

    一个。在正则表达式中,首先匹配您要查找的完整字符串(在您的情况下是主要构造函数)。不难做到:搜索大括号,单词public,然后是两个单词和一个等号等。根据这个发现的每个文本称为匹配。

    湾有时,您正在寻找的文本中可能存在重复的序列。 (在您的情况下:参数在每行中定义一行)。为此,您只需将预期序列标记为一个组,方法是用括号括起来。

    C。然后,您需要标记所找到内容的不同部分,以便您可以使用它们或在更正的文本中替换它们。这些部分也称为“组”,实际上称为“捕获组”。再次简单地用括号括起部分。 在您的情况下,您将保留第一个捕获的组(大括号)和属性的名称及其对参数的赋值。

    d。这是正则表达式:

    (\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?})(\s*?=\s*?\w*;\s*)
    
    1. ( 
          // ---- Capture1 -----
          {         
              // code: \{\s*? 
              // explained: curley bracket followed by possible whitespace
       ) 
    
    2. ( - Capture2  - previously corrected text 
          // - possible multiple lines of 'corrected' non-primary-constructors 
          // created during the find-replace process previously, 
    
          Propname = paramname;  // word,  equals-sign, word, semicolon 
          // code:  \w*\s*?=\s*?\w*\s*?;\s*?
          // explained:   \w - any alphanumeric, \s - any whitespace
          //              * - one or more times, *? - 0 or more times 
       )*?  
          // code: )*?
          // explained:  this group can be repeated zero or more times 
          // in other words it may not be found at all. 
          // These text lines are created during the recursive replacement process...
    
    3. ( 
          //  ----Capture 3-----
          // The first line of a primary constructor: 
          public type
          // code: public\s*\w*\s*  
          // explained: the word 'public' and then another word (and [whitespace]) 
        )
    
    4. (
        // ----- capture 4 -----
        Propname
         // code: \w@  
         // explained:  any amount of alphanumeric letters
       )
    
    5. (
         // ---- capture 5 ----
         { get; }
         // code: \s*?{\s*?get;\s*?\}
       )
    
    6. (
        // ---- capture 6 ----
         = propname; 
        code: \s*?=\s*?\w*;\s*
        explained: by now you should get it. 
    

替换字符串是

\1\2\4\6

这留下:

{ 
    [old corrected code] 
    [new corrected line]
    possible remaining lines to be corrected. 
  1. 记事本+ + 试错10分钟。我保证不会超过你。

  2. Visual Studio 2014 重构。但 一个。您必须将其安装在单独的VM或PC上。 MS警告您不要将其与现有代码并排安装。 湾我不确定重构是否正常工作。 [Here's an article about it][1]

  3. Visual Studio宏。我知道我知道,它们早已不复存在,但至少有两个插件可以替代它们,也许更多。我读到了他们 这个SO(StackOverflow)的讨论。 (他们提供了一些其他选择)这里:

  4. 视觉指挥官  - 免费开源Visual Studio宏运行程序加载项
  5. VSScript - Visual Studio加载项:费用50美元!!

  6. 尝试 自动Regexp示例:您给出了几个代码示例,其中您突出显示了预期结果是什么,然后是相同(或其他)代码,其中突出显示的不是预期结果。然后等待它运行示例并为您提供一些正则表达式代码。

    //用于以下代码(来自 http://odetocode.com/blogs/scott/archive/2014/08/14/c-6-0-features-part-ii-primary-constructors.aspx )

    public struct Money(字符串货币,小数) {     public string Currency {get; } =货币;     公共十进制金额{get; } =金额; } //我得到类似的东西:{++ \ w \ w [^ r-u] [^ _] ++ | [^ {] ++(?= {\ w ++ =)

  7. 在这个伟大的网站上玩正则表达式: https://www.regex101.com/

    // I first tried: \{\s*((public\s*\w*\s*)\w*(\s*?{\s*?get;\s*?})\s*?=\s*?\w*;\s*)*\}
    

主构造函数行的重复序列(“重复捕获组”)仅捕获最后一个。

  1. 使用c#代码 regex.captures 如解释 这里是另一个StackOverflow(见接受的答案)

3
2018-01-24 23:31