c# - 在 T4 中使用项目引用作为程序集路径

标签 c# .net .net-assembly t4 auto-generate

我有一个 .tt 脚本需要引用几个外部程序集。

T4 主机是否可以自动包含项目中引用的程序集 - 而不是我手动为每个程序集添加程序集指令?

例如当使用相对于 $(ProjectDir) 的路径时,从 nuget 引用程序集是一个移动目标。

使用像 $(Project)\bin\Debug\Example.dll 这样的程序集路径似乎也不是最优的——因为它要求构建之前已经成功——如果您有一个 .tt 文件在 .cs 文件中生成“ErrorGeneratingOutput”!?

更新 1:

所以我第二次尝试解决这个问题,但这次试图解决围绕“TransformOnBuild”的问题(作为旁注,我强烈推荐@kzu 的优秀项目:https://github.com/clariuslabs/TransformOnBuild)并且没有可用的 $(SolutionDir)当不通过直接从 msbuild 运行 TextTransform 时。无论如何 - 我想出了一个两步解决方案。

  1. msbuild 目标使用 WriteLinesToFile 任务生成一个 .tt 文件,其中包含基于 csproj 文件中找到的引用的新程序集指令列表。

  2. 项目中的任何其他 .tt 文件都可以包含自动生成的文件以注册项目程序集。

这是目标的示例:

<Target Name="Write_AssemblyRefs_TT" BeforeTargets="TransformOnBuild">
  <!-- A message for all to enjoy! -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;# /* AUTOGENERATED BY MSBUILD and Kern Herskind Nightingale */ #&gt;" 
    Overwrite="true" 
    Encoding="Unicode" />
  <!-- Output all assembly references with a HintPath -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;#@ assembly name=&quot;$(ProjectDir)%(Reference.HintPath)&quot; #&gt;" 
    Overwrite="false"
    Encoding="Unicode"
    Condition="'%(Reference.HintPath)' != ''" />
  <!-- Output all project references - this could fail with custom nameing/build output dirs  -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;#@ assembly name=&quot;$(ProjectDir)%(ProjectReference.RelativeDir)bin\$(Configuration)\%(ProjectReference.Name).dll&quot; #&gt;" 
    Overwrite="false"
    Encoding="Unicode" />
</Target>
<ItemGroup>
  <MyTextFile Include="AssemblyRefs.tt" />
</ItemGroup>

以及如何将其包含在 T4 文件中(简单):

<#@ include file="AssemblyRefs.tt" #>

代码生成器的代码生成:)

更新 2:

我创建了一个 Nuget 包,以便轻松添加上述汇编指令生成构建目标:https://www.nuget.org/packages/AssemblyReferencesTT/1.0.12

最佳答案

如果可以的话,我会在评论中发布这个。

问题: 不可能自动包含项目中引用的程序集,但您可以限制必须做的工作。

如果您在建议编号 1 中看到以下链接,则可以在 t4 读取之前使用 c# 定义汇编代码。这使得读取带有反射的目录并在那里加载每个程序集成为可能。所以问题是你的程序集在哪里?

List<Assembly> allAssemblies = new List<Assembly>();
string path = Assembly.GetExecutingAssembly().Location;

foreach (string dll in Directory.GetFiles(path, "*.dll"))
    allAssemblies.Add(Assembly.LoadFile(dll));
    <#@ assembly name=dll #>

这是未经测试的,但至少应该让你开始。 供引用 -> how to load all assemblies from within your /bin directory

第二部分:

  1. 使用 $(SolutionDir) 但这与 $(Project) 相同,只是低一级。 -> How do I use custom library/project in T4 text template?
  2. 使用 C# 路径实用程序在运行时导航到所需路径,但这同样可能需要先编译程序集。
  3. 在 GAC 中注册外部库。这接缝最能解决您的问题,因为您根本不必设置路径。查看 -> How to register a .Net dll in GAC?

编辑:这是一个有效的动态包含。只需在任何其他 .tt 文件中引用由此生成的 .ttinclude 结果

我用调试器测试了它,它似乎可以工作。

并更改程序集本地化以指向您需要的位置。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Net.Http" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".ttinclude" #><#

List<Assembly> allAssemblies = new List<Assembly>();
string file = Assembly.GetExecutingAssembly().Location;
if(file!= "")
{
    string path = Path.GetDirectoryName(file).TrimEnd();
    if(path != "")
        foreach (string dll in Directory.GetFiles(path, "*.dll"))
        {
            if(dll != "")
            {
                allAssemblies.Add(Assembly.LoadFile(dll));
                #>\<#<#= "@ assembly name=\""+ dll +"\" "#>\#><#="\n"#><#
            }
        }
}

#>

输出:

<#@ assembly name="C:\TEMP\3mo0m0mq.dll" #> 
 <#@ assembly name="C:\TEMP\4ybsqre3.dll" #> 
 <#@ assembly name="C:\TEMP\ao0bzedf.dll" #> 
 <#@ assembly name="C:\TEMP\bo2w102t.dll" #> 
 <#@ assembly name="C:\TEMP\c5o2syvv.dll" #> 
 <#@ assembly name="C:\TEMP\dz1fin10.dll" #> 
 <#@ assembly name="C:\TEMP\giym0gef.dll" #> 
 <#@ assembly name="C:\TEMP\hjfgqkov.dll" #> 
 <#@ assembly name="C:\TEMP\ibuz4wvb.dll" #> 
 <#@ assembly name="C:\TEMP\ilrcwa2y.dll" #> 
 <#@ assembly name="C:\TEMP\k0yeumhb.dll" #> 
 <#@ assembly name="C:\TEMP\kirzdsqp.dll" #> 
 <#@ assembly name="C:\TEMP\ksxl4f2z.dll" #> 
 <#@ assembly name="C:\TEMP\l4kja4ts.dll" #> 
 <#@ assembly name="C:\TEMP\ljgxkpo0.dll" #> 
 <#@ assembly name="C:\TEMP\lkvkmlct.dll" #> 
 <#@ assembly name="C:\TEMP\lnofhhlq.dll" #> 
 <#@ assembly name="C:\TEMP\nbqhmjqd.dll" #> 
 <#@ assembly name="C:\TEMP\oc3pxhmq.dll" #> 
 <#@ assembly name="C:\TEMP\qb43ntcu.dll" #> 
 <#@ assembly name="C:\TEMP\qlyoyhyr.dll" #> 
 <#@ assembly name="C:\TEMP\snwvtb00.dll" #> 
 <#@ assembly name="C:\TEMP\umhhb2wb.dll" #> 
 <#@ assembly name="C:\TEMP\xsyfel0b.dll" #> 
 <#@ assembly name="C:\TEMP\z1weyhko.dll" #> 

您可以使用\<# 转义 <# 字符,请参阅 this.

关于c# - 在 T4 中使用项目引用作为程序集路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25990163/

相关文章:

c# - 按升序或降序对数字或字母进行通用排序

c# - 为什么我会收到 WaitingforActivation TaskStatus

c# - new Version(AssemblyFileVersionAttribute.Version) 总是会成功吗?

c# - System.Numerics 是一个单独的程序集的原因

c# - 如何在客户端和服务器之间共享 gRPC proto 数据

c# - 销售人员记录

c# - 在本地计算机上使用 WCF 获取错误 "This collection already contains an address with scheme http"

c# - 我应该更喜欢 Func<T, TResult> 还是 Converter<TIn, TOut>?

.net - 如何使用 .NET Framework 执行 RSAES-OAEP 加密和解密?

c# - 序列化在 ScriptEngine session 中创建的类型