如何使 Roslyn Compilation 复制引用

How to make Roslyn Compilation to copy references

使用 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 永远不会复制引用。那不是编译器做的事情。在常规构建中,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);
    }