如何使Roslyn编译复制引用

本文关键字:复制 引用 编译 Roslyn 何使 | 更新日期: 2023-09-27 18:06:05

当用Roslyn编译一个项目时,一切都很好,但是因为项目引用了其他程序集,我需要将它们复制到输出目录

我有这样的代码:

var workspace = MSBuildWorkspace.Create();
var projects = workspace.OpenSolutionAsync(@"Solution.sln").Result;
var project = projects.Projects.First();
var compilation = project.GetCompilationAsync().Result;
var dllPath = Path.Combine(Directory.GetCurrentDirectory(), "Example.dll");
var pdbPath = Path.Combine(Directory.GetCurrentDirectory(), "Example.pdb");
  using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate))
    using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
    {
      var emit = compilation.Emit(dllStream, pdbStream);
    }
var assembly = Assembly.LoadFile(dllPath);

当然它只写Example.dll,但我没有找到选项来告诉编译或发出也添加引用与CopyLocal等(以自动的方式),而不需要循环遍历引用并自己做

如何使Roslyn编译复制引用

Roslyn永远不会复制引用。这不是编译器做的事情。在常规构建中,MSBuild决定是否在本地复制引用。

如果你想复制引用,你的代码需要处理。

Roslyn不复制引用。正如@Kevin Pilch所说,这不是编译器的责任。

我认为,一个叫做MSBuildWorkspace的东西应该有这种知识,即使它不采取行动。

这是一个快速修复project.FilePath,解析文件。

    private static IEnumerable<PortableExecutableReference> GetMetadataReferencesToCopy(string path, IEnumerable<MetadataReference> metadataReferences)
    {
        var references = metadataReferences
            .OfType<PortableExecutableReference>()
            .Select(x => new
            {
                Name = Path.GetFileNameWithoutExtension(x.FilePath),
                Reference = x,
            })
            .ToDictionary(x => x.Name, x => x.Reference);
        var xmldoc = new XmlDocument();
        xmldoc.Load(path);
        foreach (XmlNode item in xmldoc.GetElementsByTagName("Reference"))
        {
            var include = item.Attributes?
               .OfType<XmlAttribute>()
               .FirstOrDefault(x => x.Name == "Include")?
               .Value;
            if (include == null)
            {
                continue;
            }
            var name = new AssemblyName(include).Name;
            bool copyLocal;
            if (bool.TryParse(item.ChildNodes?
                   .OfType<XmlNode>()
                   .FirstOrDefault(x => x.Name == "Private")?
                   .InnerText, out copyLocal) &&
                references.ContainsKey(name) &&
                copyLocal)
            {
                yield return references[name];
            }
        }
    }

你可以这样调用它:

    var metadataReferences = GetMetadataReferencesToCopy(project.FilePath, project.MetadataReferences);
    foreach (var item in metadataReferences)
    {
        Console.WriteLine(item.FilePath);
    }