【问题标题】:How to programatically insert a property to a class in .cs source file?如何以编程方式将属性插入 .cs 源文件中的类?
【发布时间】:2013-03-06 09:45:52
【问题描述】:

我正在创建一个自动化工具,用于将属性插入到现有类的源代码中。例如。我有一个像这样的现有源代码:

public class MyClass 
{
   //class members goes here

}

我想修改成这样

public class MyClass 
{
   //class members goes here

   public string MyProp { get; set; }
}

并将其保存到同一个文件中。

类名、属性类型和属性名是事先知道的,可以作为操作的参数。知道如何轻松做到这一点吗?也许regex replace 可以解决这个问题,但我不知道无论源代码的新行、空格和标识策略如何,使用哪个表达式会更灵活。

编辑:我正在寻找的只是自动生成源代码,而不是在运行时操作类

【问题讨论】:

  • 这个链接可能对你有帮助:stackoverflow.com/questions/7569223/…
  • @Falaque 实际上,我正在寻找的只是自动生成源代码,而不是在运行时操作类
  • 所以你不想修改现有的源代码而是想从头开始生成类?
  • 我想将属性添加到具有现有源代码的类。
  • 你看过部分类吗?将生成的代码和手工制作的代码分开是一种很好的做法。代码生成可以使用 T4 模板来完成。

标签: c# .net regex string code-generation


【解决方案1】:

这样做的一种简洁方法是使用T4 templates 生成partial classes

T4 模板是在编译时生成代码的好方法。

开发人员不应修改这些生成的文件,而是开发人员创建另一个文件,其中包含部分类成员的附加定义。

这样您就可以一次又一次地调整和运行生成器,而不会弄乱自定义代码。

【讨论】:

    【解决方案2】:

    以下使用正则表达式的方法应该可行,尽管我认为这可能不是满足您需要的最佳方法。真的不知道,这取决于你的需求。我一直这样做(要么创建修改.cs 文件的脚本,要么创建Notepad++ 中的宏)。也许您还想看看partial classes

    string text = 
    @"namespace X {
        public class MyClass {
            //Text here
        }
    }";
    string className = "MyClass";
    string propertyType = "string";
    string propertyName = "MyProperty";
    
    string regex = string.Format(@"( *)((public?)\s*(static)?\s*class\s+{0}\s*{{)", className);
    string replacement = string.Format("$1$2\r\n\r\n$1    public {0} {1} {{ get; set; }}", propertyType, propertyName);
    
    var modified = Regex.Replace(text, regex, replacement);
    Console.WriteLine(modified);
    

    上面的代码会打印出来:

    namespace X {
        public class MyClass {
    
            public string MyProperty { get; set; }
            //Text here
        }
    }
    

    编辑: 如您所见,它正确缩进了代码。它使用包含类定义的行的相同数量的空格 + 4 个。如果要添加选项卡或其他任何内容,可以更改正则表达式。

    【讨论】:

    • 看起来不错。知道如何将属性放在课程的末尾吗?例如。 //Text here 将出现在属性顶部
    • @LouisRhys 这样如果你有一些方法/属性,新属性会出现在那些之后?
    • @LouisRhys 不幸的是,正则表达式无法做到这一点,因为它不知道类语句的 } 是什么。我认为正则表达式将毫无问题地工作 if 您在类语句的开头添加属性:/
    • 请注意,VS 2012 不再支持宏
    • @ErnodeWeerd 对不起。我的意思是“notepad++ 宏”。
    【解决方案3】:

    在运行时添加

    程序集无法在运行时更改,因此您需要在运行时生成一个 DLL 并加载它,或者您可以使用 ExpandoObject,如 SO question 中所述

    在编译时添加

    如果您不想在运行时添加代码而不是您正在寻找 CodeDom

    【讨论】:

    • 实际上,我并不想在运行时添加属性,只是以编程方式将属性添加到源代码中。
    • 或者你可以使用 fileWatch/fileSystemWatch 并在文件更改时从 cmd 行编译项目。
    【解决方案4】:

    用于在运行时和编译时之间添加

    只是想加入另一个选项。尽管在很多方面你都不想这样做,至少从你提供的很少信息来看。

    您可以使用 IL 编织。此选项发生在编译后(到 MSIL)但在运行时之前。结果是您的类获得了编译时操作的所有好处,但比 CodeDom 提供的信息要多得多。

    MSIL 编织的实现包括 PostSharp.Net(商业产品)和 Mono.Cecil(注意不要让 Mono 部分欺骗您,它也适用于 .Net)。

    优势包括:

    • 它的(运行时)与编译时方法一样快
    • 您有很多 CodeDom 丢失的信息(部分类是 CodeDom 中一个特别痛苦的问题)

    缺点包括:

    • 编织很困难(您甚至会失去编译时间检查)
    • IDE 对编织的支持很少

    【讨论】:

      【解决方案5】:

      您可以尝试cog,这是一个用 Ruby 编写的通用代码生成器。 cog 有一个 embeds 功能,非常适合您的目的。为了实现你的目标,你会像这样修改你的类

      public class MyClass 
      {
          // class members goes here
      
          // cog: auto-properties
      }
      

      然后像这样编写一个 cog 生成器(一个简短的 ruby​​ 脚本)

      embed 'auto-properties' do |c|
          "    /* whatever you return gets injected into #{c.filename} */"
      end
      

      在示例中,cEmbedContext 的一个实例。设置生成器后,您可以使用命令行调用来运行它

      $ cog gen
      Updated src/MyClass.cs - 1st occurrence of embed 'auto-properties'
      

      现在你的班级看起来像这样

      public class MyClass 
      {
          // class members goes here
      
      // cog: auto-properties {
          /* whatever you return gets injected into MyClass.cs */
      // cog: }
      }
      

      如何生成给定文件名的属性取决于您。 cog 非常灵活,还支持使用 ERB 模板生成代码。

      【讨论】:

        猜你喜欢
        • 2019-06-10
        • 1970-01-01
        • 2015-06-06
        • 1970-01-01
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多