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