.net 在Roslyn中加载可移植MetadataReference的正确方法是什么?

oymdgrw7  于 12个月前  发布在  .NET
关注(0)|答案(3)|浏览(112)

我正在尝试编译一些针对可移植的.Net库构建的代码,并试图确定将可移植程序集作为MetadataReference对象加载的正确方法。
例如,我可以像这样加载程序集,它将工作:

var analyzerCode = "// Some analyzer code here";
var syntaxTree = CSharpSyntaxTree.ParseText(analyzerCode);

string assemblyName = System.IO.Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
    MetadataReference.CreateFromFile(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Runtime.dll"),
    MetadataReference.CreateFromFile(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Diagnostics.Debug.dll"),
    MetadataReference.CreateFromFile(typeof(System.Collections.Immutable.ImmutableArray).Assembly.Location),
    MetadataReference.CreateFromFile(typeof(Microsoft.CodeAnalysis.CSharp.CSharpCompilation).Assembly.Location),
    MetadataReference.CreateFromFile(typeof(Microsoft.CodeAnalysis.Workspace).Assembly.Location)
};

CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

using (var ms = new MemoryStream())
{
    EmitResult result = compilation.Emit(ms);
    // Check the result for errors and work with it
}

显然,这不是很可移植的代码,因为我使用的文件路径可能只在我的机器上工作。如果我执行以下操作:

MetadataReference.CreateFromFile(typeof(object).Assembly.Location),

我得到以下例外:
CS0012:在未引用的程序集中定义了类型“Object”。您必须添加对程序集“System.Web.Nov,Version=4.0.0.0,Culture=neutral,PublicKeyToken= b03f5f7f11d50a3a”的引用。
我相信这是因为运行此代码的解决方案是4.6程序集,因此typeof(object)指向4.6 System.dll。
所以我的问题是,指定可移植程序集作为Roslyn编译对象的MetadataReference示例的正确方法是什么?

vnjpjtjt

vnjpjtjt1#

如果你的编译同时引用了“完整的”框架4.5或4.6,并且你还引用了可移植的库,你还需要添加对façade程序集的引用来在它们之间建立桥梁。您可以在以下网址找到它们:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades

在这里,你应该用你的目标桌面框架的任何版本来替换v4.6。您应该循环遍历该目录,并为其中看到的所有程序集添加一个引用。

mspsb9vt

mspsb9vt2#

找到程序集的路径并指定要加载的可移植库。可能看起来像这样:

var dotNetAssemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
var references = new MetadataReference[]
    {
        MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "MY_PORTABLE_FILE_TO_BE_LOADED"))
    };
oaxa6hgo

oaxa6hgo3#

使用以下nuget包:
https://github.com/jaredpar/basic-reference-assemblies
参考:https://github.com/dotnet/roslyn/issues/49498
这个存储库现在生成易于使用的参考程序集DLL。README.md有很多细节,但简而言之,使用那里定义的NuPkg,您可以在内存中创建编译,如下所示:

var code = @"
using System;
static class Program
{
    static void Main()
    {
        var tuple = (Part1: ""hello"", Part2: ""world"");
        Console.WriteLine($""{tuple.Part1} {tuple.Part2}"");
    }
}
";

var compilation = CSharpCompilation
    .Create(
        "HelloWorld.dll",
        new[] { CSharpSyntaxTree.ParseText(code) },
        references: ReferenceAssemblies.Net50);

using var fileStream = new FileStream(@"p:\temp\helloworld.exe", FileMode.Create, FileAccess.ReadWrite);
var emitResults = compilation.Emit(fileStream);

相关问题