5

I am creating an automation tool for inserting properties to existing class's source code. E.g. I have an existing source code like this:

public class MyClass 
{
   //class members goes here

}

I want to modify it to become like this

public class MyClass 
{
   //class members goes here

   public string MyProp { get; set; }
}

and save it to the same file.

The class name, property type and property name will be known before hand and can be considered parameters of the operation. Any idea how to do this easily? Perhaps regex replace will work for this, but I don't know which expression to use that will be flexible regardless of the source code's new line, whitespace and identation policy.

EDIT: What I'm looking for is simply automatically generating the source code, not manipulating classes during runtime

Louis Rhys
  • 34,517
  • 56
  • 153
  • 221
  • probably this link should help you: http://stackoverflow.com/questions/7569223/programmatically-insert-a-method-call-on-each-property-of-a-class – Falaque Mar 18 '13 at 05:45
  • @Falaque Actually, what I'm looking for is simply automatically generating the source code, not manipulating classes during runtime – Louis Rhys Mar 18 '13 at 05:49
  • so you don't want to modify the existing source code instead want to generate class from scratch? – Falaque Mar 18 '13 at 05:56
  • I want to add property to a class with existing source code. – Louis Rhys Mar 18 '13 at 05:57
  • 2
    Did you have a look at partial classes? It is a good practice to keep generated code and handcrafted code separate. Code generation could be done using T4 templates. – Emond Mar 18 '13 at 06:02
  • maybe have a look at [Microsoft® “Roslyn” CTP](http://msdn.microsoft.com/en-us/roslyn) it's a compiler as a service, the alternative to using regex would be the [codedom codeparser](http://msdn.microsoft.com/en-us/library/y2tzf7yk.aspx) and that seems like a lot of work, I think that the compiler as a service would take less time to get started with –  Mar 18 '13 at 06:27

5 Answers5

5

A clean way of doing this, is by using T4 templates to generate partial classes.

T4 templates are a good way to generate code at compile time.

These generated files should not be modified by the developer, instead the developer creates another file with additional definitions of members of the partial class.

That way you can tweak and run the generator again and again without messing with the custom code.

Emond
  • 50,210
  • 11
  • 84
  • 115
3

The following approach using regular expressions should work, although I don't think this could be the best way of doing what you need. Don't really know, that depends on your needs. I do it all the time (either creating scripts that modify the .cs files, or macros from Notepad++). Perhaps you might also want to take a look at 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);

The above code will print:

namespace X {
    public class MyClass {

        public string MyProperty { get; set; }
        //Text here
    }
}

Edit: As you can see, it indents the code correctly. It uses the same number of spaces of the line that contains the class definition + 4 more. If you want to add a tab, or whatever, you can change the regex.

Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124
  • looks nice. Any idea how to put the property at the end of the class? E.g. `//Text here` will appear on top of the property – Louis Rhys Mar 18 '13 at 06:25
  • @LouisRhys so that if you have some methods/properties, the new property will appear after those? – Oscar Mederos Mar 18 '13 at 06:27
  • @LouisRhys Unfortunately, doing that is not possible with regular expressions, since **it won't know what is the } of the class statement**. I think regular expressions will work without problems *if* you add the property at the begining of the class statement :/ – Oscar Mederos Mar 18 '13 at 06:33
  • Note that macros are no longer supported in VS 2012 – Emond Mar 18 '13 at 06:37
  • @ErnodeWeerd I'm sorry. What I meant was "`notepad++` macros". – Oscar Mederos Mar 18 '13 at 06:39
  • I see. May I know the purpose of `[^{{]+{{)` at the end of your regex? – Louis Rhys Mar 18 '13 at 06:40
  • @LouisRhys The regular expression should really be `[^{]+{`, but I had to escape `{` and `}` because I was using `string.Format`. It means: Match anything (except `{`) one or more times, and then a `{`. I did that to match spaces after the class name, tabs, new lines, etc. although that can be converted to `\s*?{`. In fact, I'm going to edit it. – Oscar Mederos Mar 18 '13 at 06:43
2

For Adding At RunTime

Assembly can not be changed at run time so either you need to generate a you DLL at runtime and load it or you can use ExpandoObject as described in this SO question

For Adding At Compile Time

if you do not want to add code at runtime than you are exactly looking For CodeDom

Community
  • 1
  • 1
TalentTuner
  • 17,262
  • 5
  • 38
  • 63
  • Actually, I am not looking to add property in runtime, only add property programatically to a source code. – Louis Rhys Mar 18 '13 at 05:45
  • Or you could use a fileWatch/fileSystemWatch and compile the project from the cmd line when the file is changed. – Rhexis Mar 18 '13 at 05:46
0

For Adding Between Runtime and Compile time

Just wanted to throw in another option. Although in soooo many ways you don't want to do it, at least from what little information you gave.

You can use IL weaving. This option happens AFTER compile (to MSIL) but BEFORE runtime. The effects are that your class gets all the benefits of compile time manipulation, but gives you much more information than CodeDom could.

Implementations of MSIL weaving include PostSharp.Net(Commercial product) and Mono.Cecil (N.B. Don't let the Mono part fool you, it works on .Net as well).

Advantages include:

  • Its (runtime) as fast as a compile time method
  • You have a lot of information that CodeDom loses (partial classes are an especially painful problem in CodeDom)

Disadvantages include:

  • Weaving is hard (you even lose compile time checking)
  • There is very little IDE support for weaving
Aron
  • 15,464
  • 3
  • 31
  • 64
0

You might try cog, a general purpose code generator written in Ruby. cog has an embeds feature which would suit your purpose well. To achieve your goal you would modify your class like this

public class MyClass 
{
    // class members goes here

    // cog: auto-properties
}

then write a cog generator (a short ruby script) like this

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

In the example, c is an instance of EmbedContext. Once you've setup a generator you run it with a command-line invocation

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

and now your class looks like this

public class MyClass 
{
    // class members goes here

// cog: auto-properties {
    /* whatever you return gets injected into MyClass.cs */
// cog: }
}

It's up to you how to generate the properties given the filename. cog is pretty flexible and also supports using ERB templates to generate code.

Kevin Tonon
  • 965
  • 10
  • 18