c# - 在运行时(构建时)创建 T4 模板?

标签 c# .net templates code-generation t4

我们正在构建一个内部应用程序,它需要生成 HTML 文件以上传到 eBay 列表中。我们希望使用模板引擎根据我们预定义的数据库和静态字段生成 HTML 文件。该模板还需要具有逻辑功能(if-then、foreach 等)。

我们看过 T4,它看起来很完美,但我们没有看到任何关于它是否具有在运行时使用的能力,以便用户可以创建 T4 模板,然后应用程序可以“编译”它并生成最终的 HTML 文件。这可能吗?如何实现?

如果没有,我们是否应该考虑其他具有所有这些功能的框架?

最佳答案

我有一组类似的类用于此,将模板化文本生成嵌入到软件中。

基本上,它像旧式 ASP 一样工作,您将 C# 代码包围在 <%...%> 中 block ,您可以使用 <%= expression %> 发出结果.

您可以将单个对象传递到模板代码中,当然可以是您喜欢的任何对象类型,或者只是一个参数数组。如果要执行自定义代码,也可以引用自己的程序集。

下面是发出一个类的样子:

<%
var parameters = (string[])data;
var namespaceName = parameters[0];
var className = parameters[1];
%>
namespace <%= namespaceName %>
{
    public class <%= className %>
    {
    }
}

你当然可以遍历事物:

<% foreach (var parameter in parameters) { %>
<%= parameter %>
<% } %>

并将代码放入 if block 等

类库在此处的 CodePlex 上发布:

以及 NuGet .

项目自带例子,下载源码或browse it online .

也在这里通过电子邮件回答问题,以供其他人查看:

  1. 所有类型的 C# 代码适合方法调用 都可以在模板中编译。它运行正常的 C# 3.5 代码,这意味着没有人为限制。唯一要知道的是,任何包含要发出的模板代码的 if、while、for、foreach 等代码都必须使用大括号,不能使用单行 if-then 类型 block 。请参阅下文了解方法调用限制。
  2. data参数对应于作为参数传递给 .Generate(x) 的任何内容来自您的应用程序的方法,并且属于同一类型。如果你传入一个你在自己的类库中定义的对象,你需要添加对模板代码的引用才能正确访问它。 ( <%@ reference your.class.library.dll %> )
  3. 如果您重用已编译的模板,它本质上只是对类的方法调用,对 .Generate() 的实际调用不会产生额外的开销。 .如果你不打电话 .Compile()你自己,第一个电话.Generate()会处理的。另请注意,代码在单独的应用程序域中运行,因此与来回复制参数和结果相关的编码开销很小。但是,代码以正常的 JITted .NET 代码速度运行。

if block 的例子:

<% if (a == b) { %>
This will only be output if a==b.
<% } %>

代码格式也没有人为限制,选择最适合您的样式:

<%
    if (a == b)
    {
%>
This will only be output if a==b.
<%
    }
%>

请注意,模板的所有非代码部分几乎都将按原样输出,这意味着制表符和 %> 之后的类似内容 block 也将被输出。

有一个限制,您编写的所有代码都必须放在一个方法调用中。

让我解释一下。

模板引擎的工作方式是生成一个 .cs 文件并将其提供给 C# 编译器,这个 .cs 文件大致如下所示:

using directives

namespace SomeNamespace
{
    public class SomeClass
    {
        public string Render(object data)
        {
            ... all your code goes here
        }
    }
}

这意味着您不能定义新类、新方法、类级字段等。

但是,您可以使用匿名委托(delegate)在内部创建函数。例如,如果您想要一种统一的格式日期方式:

Func<DateTime, string> date2str = delegate(DateTime dt)
{
    return dt.ToString("G");
};

然后您可以在其余的模板代码中简单地使用它:

<%= date2str(DateTime.Now) %>

我唯一的要求是您不要将文件上传到网络上并声称您编写了代码,除此之外您可以自由地使用它做任何您想做的事情。

编辑 23.04.2011:修复了指向 CodePlex 项目的链接。

关于c# - 在运行时(构建时)创建 T4 模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2307567/

相关文章:

c# - 为什么我无法使用 SqlCommand 创建触发器?

c# - 带有 Entity Framework 的 SQLite DATETIME 列

c# - ElasticSearch中的单词匹配

c# - 在 Powershell 中使用 C++CLI .dll 作为程序集

c# - 有关结构实现接口(interface)时发生的情况的详细信息

c++ - 从具有可变参数的模板类继承

javascript - Meteor:使用 ReactiveVar 创建一个加载小部件来订阅用户集合

c# - C# .Net Office 365 API 入门

c# - InternalClientWebSocket 实例无法用于通信,因为它已转换为 'Aborted' 状态

c++ - 实现 `to_xstring()` 来合并 `to_string()` 和 `to_wstring()`