将 t4 模板的输出设置为嵌入资源

Set output of t4 template as embedded resource

提问人:awj 提问时间:2/21/2023 最后编辑:awj 更新时间:2/23/2023 访问量:41

问:

我已经构建了一个 t4 模板来输出多个文件,但我需要这些文件是嵌入内容。

t4 是否提供了一种开箱即用的方法?

如果没有,是否可以通过将每个文件的元素切换为元素来修改项目文件?<Content><EmbeddedResource>

C# T4

评论


答:

0赞 awj 2/23/2023 #1

以下是我如何将 a 设置为嵌入式资源: 在 T4 模板中,我有一个函数,它接受对象和一个表示 T4 模板本身的对象 - 可能有一种更简单的方法,但我使用...ProjectItemProjectFileInfoFileInfo

var templateFileInfo = new FileInfo(this.Host.TemplateFile);

之所以使用模板,是因为我们需要生成的文件(我的 T4 模板输出多个文件),这些文件是在解决方案中的模板文件下“生成的”。FileInfo

[实际上,我在这里想要的是一个表示模板的 ProjectItem,这样我就可以循环访问自动生成的子项。如果有更好的方法,请发表评论。]

一旦我拥有了表示每个 T4 生成的文件的对象,我就会枚举每个集合,直到找到该集合的属性;然后使用常量将其设置为“嵌入资源”。ProjectItemProperties"BuildAction"ProjectItem

private void SetGeneratedFilesAsEmbeddedResources(Project project, FileInfo templateFileInfo)
{
    const string propBuildAction = "BuildAction";

    var generatedProjectItems = GetGeneratedProjectItems(project, templateFileInfo).ToList();

    foreach (var generatedProjectItem in generatedProjectItems)
    {
        var props = generatedProjectItem.Properties;
        if ((VSLangProj.prjBuildAction)props.Item(propBuildAction).Value != VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource)
        {
            props.Item(propBuildAction).Value = VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource;
        }
    }
}

private IEnumerable<ProjectItem> GetGeneratedProjectItems(Project project, FileInfo templateFileInfo)
{
    var templateParentFolder = GetTemplateParentFolder(project, templateFileInfo);

    foreach (ProjectItem item in templateParentFolder.ProjectItems)
    {
        if (item.Kind != EnvDTE.Constants.vsProjectItemKindPhysicalFile || item.Name != templateFileInfo.Name)
        {
            continue;
        }

        foreach (ProjectItem generatedItem in item.ProjectItems)
        {
            yield return generatedItem;
        }
    }
}

private ProjectItem GetTemplateParentFolder(Project project, FileInfo templateFileInfo)
{
    var containingFolderName = templateFileInfo.Directory.Name;

    foreach (ProjectItem item in project.ProjectItems)
    {
        if (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder && item.Name == containingFolderName)
        {
            return item;
        }
    }
    
    throw new Exception($"Cannot execute {templateFileInfo.Name} - Unable to locate the \"{containingFolderName}\" folder at the root level.");
}