如何从 $(TargetDir) 这样的宏路径中获取真实路径?

问题描述 投票:0回答:1

在 t4 文本模板中,我尝试使用以下方式加载 dll:

Assembly.LoadFile(dllPath)

但它返回错误:需要绝对路径信息

dll路径为:

var dllPath = "$(TargetDir)Project.dll"
$(SolutionDir)Project\\bin\\debug\\Project.dll

如何将 "$(TargetDir)Project.dll" 转换为真正的形式

"C:\Users\....\Project.dll"
,然后再将其发送到
Assembly.LoadFile

c# reflection path t4
1个回答
1
投票

在 T4 中,我使用 ttinclude 来禁用结果覆盖,仅在使用名为“RegenCodeFiles”的特定命名解决方案配置时允许它继续生成代码。

有几种不同的方法可以解决您可能会发现有用的路径,以及查看包文件夹的程序集解析器(它是硬编码的,应该寻找 nuget.config)。

我要警告的一件事(只是因为这是一个麻烦的工作流程)是尝试引用 TT 中的程序集,而 TT 是该程序集的一部分。

包含的调用方式如下:

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ include file="CodeGenHelpers.ttinclude" #>
var regenHelper = new CodeGenHelpers(Host);
regenHelper.SetupBinPathAssemblyResolution();

if (regenHelper.ShouldRegenerate() == false)
{
    Debug.WriteLine($"Not Regenerating File");
    var existingFileName = Path.ChangeExtension(Host.TemplateFile, "cs"); 
    var fileContent = File.ReadAllText(existingFileName);
    return fileContent;
}

Debug.WriteLine($"Regenerating File");
// ...rest of T4

CodeGenHelpers.ttinclude

<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
<#@ assembly Name="EnvDTE" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#+

    public class CodeGenHelpers
    {
        private static string _ConfigName;
        private static bool? _ShouldRegenerate;
        private ITextTemplatingEngineHost _Host;
        private static DTE _Dte;

        public CodeGenHelpers(ITextTemplatingEngineHost host)
        {
            _Host = host;
        }

        public  bool ShouldRegenerate()
        {
            if (_ShouldRegenerate.HasValue == false)
            {
                var configName = GetConfigName();   
                _ShouldRegenerate = "RegenCodeFiles".Equals(configName, StringComparison.OrdinalIgnoreCase);
            }

            return _ShouldRegenerate.Value;
        }

        public string GetConfigName()
        {
            if (string.IsNullOrWhiteSpace(_ConfigName))
            {
                _ConfigName = GetDte().Solution.SolutionBuild.ActiveConfiguration.Name;
            }
            return _ConfigName;
        }

        public DTE GetDte()
        {
            if (_Dte == null)
            {
                var serviceProvider = _Host as IServiceProvider;
                _Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
            }
            return _Dte;
        }

        public void SetupBinPathAssemblyResolution()
        {
            AppDomain.CurrentDomain.AssemblyResolve += ResolveMeh;
        }

        //load from nuget packages first
        public Assembly ResolveMeh(object sender, ResolveEventArgs args)
        {
            var currentFolder = new FileInfo(_Host.ResolvePath(_Host.TemplateFile)).DirectoryName;
            var configName = GetConfigName();
            //probably look at the project properties in DTE, but whatever
            var d = _Dte;
            var assemblyName = new AssemblyName(args.Name).Name + ".dll";
            var assemblyLoadFolder = Path.Combine(currentFolder, $"bin\\{configName}");
            var assemblyPath = Path.Combine(assemblyLoadFolder, assemblyName);
            if (System.IO.File.Exists(assemblyPath) == true) 
            {
                var assembly = Assembly.LoadFrom(assemblyPath);
                return assembly;
            }

            //there are nuget services for vs, but they are installed via nuget package, 
            // which is what this is looking for so I dont know if it will work. 
            // https://www.nuget.org/packages/NuGet.VisualStudio


            var solutionFilePath = GetDte().FullName;
            var solutionFile = GetDte().FileName;
            var solutionFolder = solutionFilePath.Replace(solutionFile, string.Empty);
            var packagesFolder = System.IO.Path.Combine(solutionFolder, "packages");
            var files = System.IO.Directory.GetFiles(packagesFolder, assemblyName, SearchOption.AllDirectories);
            if (files.Length > 0)
            {
                var assembly = Assembly.LoadFrom(files[0]); //prob also check target fw
                return assembly;
            }
            
            return null;
        }

    }

#>
© www.soinside.com 2019 - 2024. All rights reserved.