How to generate code based on another class?
Asked Answered
B

4

9

To create our test data, we use the following variation of the Builder pattern (simplified example!):

Sample class:

public class Person
{
   public string Name { get; set; }
   public string Country { get; set; }
}

The builder:

public class PersonBuilder
{
    private string name;
    private string country;

    public PersonBuilder()
    {
        SetDefaultValues();
    }

    private void SetDefaultValues()
    {
        name = "TODO";
        country = "TODO";
    }

    public Person Build()
    {
        return new Person
                   {
                       Name = name,
                       Country = country
                   };
    }

    public PersonBuilder WithName(string  name)
    {
        this.name = name;            
        return this;
    }

    public PersonBuilder WithCountry(string country)
    {
        this.country = country;
        return this;
    }
}

NOTE: The context of the example itself is not relevant. The important thing here is how in the example, the a builder class like PersonBuilder can completely be generated by looking at the entity class (Person) and applying the same pattern - see below.

Now imagine that the person class has 15 properties instead of 2. It would take some monkeywork to implement the builder class, while theoretically, it could automatically be generated from the Person class. We could use code generation to quickly set up the builder class, and add custom code later if needed.

The code generation process would have to be aware of the context (name and properties of the person class), so simple text-based code generation or regex magic doesn't feel right here. A solution that is dynamic, not text-based and can be triggered quickly from inside visual studio is preferred.

I'm looking for the best way to perform code generation for scenarios like this. Reflection? Codesmith? T4 templates? Resharper Live templates with macros?

I'm looking forward to see some great answers :)

Bluebottle answered 22/3, 2011 at 14:8 Comment(0)
S
2

The T4 solution is a well Visual Studio integrated option. You can use reflection inside the T4 template to actually generate the code.

Sensate answered 22/3, 2011 at 14:12 Comment(0)
B
2

We added a feature in CodeSmith Generator 5.x that allows you to generate off of existing code. Please take a look at that documentation here. Also you can use reflection or any .NET library in a CodeSmith Generator Template.

Thanks -Blake Niemyjski

Battleax answered 23/3, 2011 at 16:26 Comment(0)
A
0

If it is for test only, consider a mocking framework like RhinoMocks:

internal class PersonBuilder
{
    private MockRepository _mockRepository;
    private IPerson _person;

    public PersonBuilder()
    {
        _mockRepository = new MockRepository();
        _person = _mockRepository.Stub<IPerson>();
    }

    public PersonBuilder WithName(string name)
    {
        _person.Name = name;
        return this; 
    }

    public PersonBuilder WithCountry(string Country)
    {
        _person.Country= Country;
        return this;
    }

    public IPerson Build()
    {
        _mockRepository.ReplayAll();
        return _person; 
    }

}

This way your builder can evolve along with your need. Further, you don't need to change your Build method. Just add "WithX" methods.

Alain answered 23/3, 2011 at 14:11 Comment(1)
We already use mocking extensively in our unit tests, but I never thought of using mocks for this though :). I think it would be a great way to solve this particular problem, but not the general question, which has a broader scope than just tests. But thanks a lot for this answer anyway!Bluebottle
M
0

Have a look into the ABSE modeling approach and its IDE, AtomWeaver. ABSE is a template-based modeling and code generation framework, where a model (has nothing to do with UML or MDA) is created by applying "building blocks" (Atoms). These Atoms are template/program hybrids and are context-aware: an Atom can generate code according to its placement on the tree and on the presence/absence of certain Atoms.

The model host (AtomWeaver in this case) will "execute" the model in order to obtain the desired source code. The model can be "the source": change the model and regenerate as many times as necessary.

AtomWeaver is not integrated into Visual Studio, but can work alongside it without any problems.

Mulford answered 24/3, 2011 at 15:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.