9

为了创建我们的测试数据,我们使用以下 Builder 模式的变体(简化示例!):

示例类:

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

建设者:

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;
    }
}

注意:示例本身的上下文不相关。这里重要的是在示例中,如何通过查看实体类 (Person) 并应用相同的模式来完全生成像 PersonBuilder 这样的构建器类 - 见下文。

现在假设 person 类有 15 个属性而不是 2 个。实现 builder 类需要一些功夫,而理论上,它可以从 Person 类自动生成。我们可以使用代码生成来快速设置构建器类,并在需要时添加自定义代码。

代码生成过程必须知道上下文(person 类的名称和属性),因此简单的基于文本的代码生成或正则表达式魔法在这里并不合适。首选动态解决方案,而不是基于文本的解决方案,并且可以从 Visual Studio 内部快速触发。

我正在寻找为此类场景执行代码生成的最佳方法。反射?密码匠?T4 模板?带有宏的 Resharper Live 模板?

我期待看到一些很棒的答案:)

4

4 回答 4

2

T4 解决方案是一个很好的 Visual Studio 集成选项。您可以在 T4 模板中使用反射来实际生成代码。

于 2011-03-22T14:12:09.877 回答
2

我们在CodeSmith Generator 5.x中添加了一项功能,允许您从现有代码生成。请在此处查看该文档。您还可以在 CodeSmith 生成器模板中使用反射或任何 .NET 库。

谢谢-布莱克·涅米斯基

于 2011-03-23T16:26:48.737 回答
0

查看ABSE建模方法及其 IDE AtomWeaver。ABSE 是一个基于模板的建模和代码生成框架,其中模型(与 UML 或 MDA 无关)是通过应用“构建块”(Atoms)来创建的。这些 Atom 是模板/程序混合体,并且是上下文感知的:Atom 可以根据其在树上的位置以及某些 Atom 的存在/不存在来生成代码。

模型主机(在本例中为 AtomWeaver)将“执行”模型以获得所需的源代码。模型可以是“源头”:更改模型并根据需要多次重新生成。

AtomWeaver 没有集成到 Visual Studio 中,但可以毫无问题地与它一起工作。

于 2011-03-24T15:41:46.910 回答
0

如果仅用于测试,请考虑使用类似 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; 
    }

}

这样,您的构建器可以随着您的需要而发展。此外,您不需要更改 Build 方法。只需添加“WithX”方法。

于 2011-03-23T14:11:41.920 回答