有没有什么可以使T4代码更干净...干净?

Ear*_*rlz 8 c# t4 refactoring unit-testing code-generation

我有一个相当复杂的东西塞进T4模板.基本上我采取类似的东西

{= foo =}更多文字...

并将其转换为类(视图),如下所示:

public class MyView
{
  public string foo{get;set;}
  public string Write()
  {
    return foo+@" more text...";
  }
}
Run Code Online (Sandbox Code Playgroud)

生成的代码当然要复杂得多.无论如何,T4模板现在超过600行代码,并且真正变得难以管理.我认为主要问题是混合代码和"内容"(即静态代码).我不确定如何干净地解决这个问题(当然不会影响生成的代码).我也没有看到任何可行的单元测试我的T4代码的方法,除了简单地测试它的T4执行错误.当然,似乎几乎不可能测试它生成的代码.

我可以使用任何"模型 - 视图"类型的框架或技术来使我的T4模板代码更干净吗?

Jus*_*mer 5

恕我直言,编写复杂模板时最重要的两个概念是

  1. 分离模型和视图 - 这有助于将模板逻辑保持在最低限度(通常是导致维护问题).我个人认为这不需要一个框架,它只需要你这样做.
  2. 部分是你的朋友 - 我通常使用T4从模型生成框架代码.特定行为可能不值得投入模型,更好地通过使用部分类或方法来允许该行为.

不那么重要但很好

  1. 使代码搜索 -我不靠T4附加组件,因为我觉得他们没有足够好,以便浏览我必须使代码搜索代码缺乏智能感知的.它可以像调用Column属性Name一样简单,我称之为ColumnName.
  2. 在输出中插入"tags" - 可以更轻松地找到生成该部分输出的代码.

分离模型/视图的示例:

<#
    // Model for Dependency Pooperties
    Model = new []
    {
        new ClassDefinition ("MyDataGrid")
            {
                P ("CultureInfo"            , "CultureInfo"),
                P ("Pen"                    , "CellBorderPen"),
                P ("IEnumerable<object>"    , "Rows"),
                C ("WColumnDefinition"      , "Columns"),
            },
    };
#>
// Include the view
<#@ include file="..\T4\DependencyProperties.ttinclude" #>
Run Code Online (Sandbox Code Playgroud)

然后,视图遍历模型并生成依赖项属性.

然后,依赖项属性的行为将作为部分方法实现

    partial void Changed_Columns(
        ObservableCollection<WColumnDefinition> oldValue, 
        ObservableCollection<WColumnDefinition> newValue
        )
    {
        HookUpColumns(oldValue, null);
        HookUpColumns(newValue, this);            
    }
Run Code Online (Sandbox Code Playgroud)

请注意,将此特定行为放入模型会使模型复杂化.

最后; 即使是一个称职的程序员也需要时间才能胜任地编写元程序.我花了多次尝试之前,我来到了一个风格,我认为这是维护的,但对我来说是值得的,因为我可以出货质量更快.

我希望这有帮助...

PS.我不认为有人会认为T4是优雅的,但它仍然是有用的.


Ear*_*rlz 1

经过长途跋涉,我终于将第一个单元测试签入了我的 T4 模板。基本上,我所做的是抽象出一个“视图”(实际的 T4 模板)和“逻辑”(生成代码的内容,但实际上并不输出它,也不依赖于 T4)

然后我更进一步,使用了一个大技巧来实现,以便我的逻辑文件可以在 T4 之外编译。这产生了很好的效果,使得智能感知和编译器错误能够正常工作。它还允许我通过简单地引用项目来从单元测试访问我的逻辑类。

如果您需要有关如何执行此操作的详细信息,我在我的博客上写了一篇包含代码示例(之前/之后)和示例单元测试的文章。