【发布时间】:2011-05-31 18:48:28
【问题描述】:
我有一个 u1 类型的对象 User 类。用户有一个属性name。如何将u1 传递给 T4 模板?我正在尝试做一些非常简单的事情:
User u1 = new User("John");
模板脚本:
Hello <# u1.Name #>
【问题讨论】:
我有一个 u1 类型的对象 User 类。用户有一个属性name。如何将u1 传递给 T4 模板?我正在尝试做一些非常简单的事情:
User u1 = new User("John");
模板脚本:
Hello <# u1.Name #>
【问题讨论】:
我们做了类似的事情。我们的解决方案包含以下要素:
自定义主机由模板本身想要调用方法的对象聚合。
interface ICallbackInterface
{
void CallbackFxn();
}
[Serializable]
public class MyCustomHost : ITextTemplatingEngineHost, ITextTemplatingSessionHost, IStencilFileRecordManagement
{
private ICallbackInterface callback = null;
public MyCustomHost(ICallbackInterface cb)
{
callback = cb;
}
public void CallbackFxn()
{
callback.CallbackFxn();
}
}
public abstract class MyTemplateBase : TextTransformation
{
public virtual MyCustomHost CustomHost
{
get
{
dynamic metame = this;
MyCustomHost rval = null;
try
{
/// <summary>
/// The "Host" property will be added to the generated class by the T4 environment whenever a
/// "hostspecific" template is processed.
/// </summary>
rval = metame.Host as MyCustomHost;
}
catch (RuntimeBinderException e)
{
logger.ErrorException(
"Received the following exception while processing a stencil template", e);
}
return rval;
}
}
}
现在,在我们的任何模板中,我们都可以使用自定义主机属性调用实际启动处理的对象上的方法,例如:
<# CustomHost.CallbackFxn(); #>
此外,我们不使用 VS 中的 T4 或使用单独的可执行文件 - 我们链接到 Microsoft.VisualStudio.TextTemplating.10.0 和 Microsoft.VisualStudio.TextTemplating.Interfaces.10.0 程序集。
编辑
我们使用 T4 模板允许用户定义自己的插件,以便在我们的产品工作流程中的特定步骤中使用。所以用户模板被上传到我们的系统,并像这样处理:
using Microsoft.VisualStudio.TextTemplating;
class UserPluginWorkflowComponent : ICallbackInterface
{
public void CallbackFxn()
{
// invoked by user plugin
}
public void ExecuteUserPlugin()
{
MyCustomHost host = new MyCustomHost(this);
host.TemplateFileValue = "UserPluginTemplateFilename";
Engine engine = new Engine();
string pluginResult = engine.ProcessTemplate(
userPluginTemplateFileContents,
host);
if (!host.Errors.HasErrors)
{
// use pluginResult in some meaningful way
}
}
}
【讨论】:
你想在你的模板中使用它吗?然后您需要添加对包含该类型的程序集的引用。您不能简单地将现有引用传递给 T4 引擎,除非您以某种非常非正统的方式自己托管它(我从未见过有人尝试这样做)。即使你走了这么远并且做到了,你会如何运行它?这个参考应该来自哪里?
使用 T4 模板中的类型就像添加引用或将其复制/粘贴到类存根 <#+ /*stuff goes here*/ #> 中一样简单。
【讨论】:
You cannot simply pass existing reference to the T4 engine unless you host it yourself 吗?另外,只是想让你知道,.tt 文件和用户类都是同一个解决方案的一部分
T4 模板在一个步骤中处理,因此模板需要在其运行期间获得所需的一切,因为您不会真正将任何东西“传递”到它们中。由于模板是文本,我通常只会在文件顶部设置一些开发人员可以设置的参数。如果您需要用户输入,您可以弹出一个窗口,但是在生成代码时听起来很烦人。
另一种解决方案是使用自定义模板,该模板在您的 t4 模板中使用模板替换,类似于许多已安装模板的工作方式。
【讨论】:
run时,它会使用对象的属性来输出文本。
假设您希望在某些应用程序或工具中拥有最终运行模板的代码,然后使用运行时(预处理)模板,其中包含在 类功能块中定义的自定义属性或 指令应该给你你想要的。
在此处查看文档:http://msdn.microsoft.com/en-us/library/gg586944.aspx
【讨论】:
嘿 - 您需要在 T4 脚本中设置值等,因此 User 初始化必须发生在 <# #> 标记内,这会将您的示例变成类似于
<# User u1 = new User() { .Name = "John" } #>
Hello <# u1.Name #>
如上所述,您可能还需要导入命名空间。我在 TT 文件的开头使用了以下语句来访问 System.Data:
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ assembly name="System.Data" #>
【讨论】: