【发布时间】:2020-01-21 19:25:12
【问题描述】:
我正在尝试创建一个可重用的 .NET Standard 2.0 库,该库使用 Roslyn 在运行时将代码动态编译为内存中的程序集。这个动态创建的程序集包含派生自作为库一部分的基类的类。我通过引用库的应用程序中的反射来实例化它们。项目结构如下:
假设我的 netstandard2.0 库中有以下类型:
namespace MyLibrary
{
public abstract class BaseClass
{
public abstract int CalculateSomething();
}
}
然后我在 .NET Core 2.2 项目中创建以下单元测试:
namespace NetCore2_2.Tests
{
public static class RoslynTests
{
[Fact]
public static void CompileDynamicallyAndInvoke()
{
// Create syntax tree with simple class
var syntaxTree = CSharpSyntaxTree.ParseText(@"
using System;
using MyLibrary;
namespace Foo
{
public sealed class Bar : BaseClass
{
public override int CalculateSomething()
{
return (int) Math.Sqrt(42);
}
}
}");
// Create compilation, include syntax tree and reference to core lib
var compilation = CSharpCompilation.Create(
"MyDynamicAssembly.dll",
new[] { syntaxTree },
new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(BaseClass).Assembly.Location)
},
new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release)
);
// Compile it to a memory stream
var memoryStream = new MemoryStream();
var result = compilation.Emit(memoryStream);
// If it was not successful, throw an exception to fail the test
if (!result.Success)
{
var stringBuilder = new StringBuilder();
foreach (var diagnostic in result.Diagnostics)
{
stringBuilder.AppendLine(diagnostic.ToString());
}
throw new XunitException(stringBuilder.ToString());
}
// Otherwise load the assembly, instantiate the type via reflection and call CalculateSomething
var dynamicallyCompiledAssembly = Assembly.Load(memoryStream.ToArray());
var type = dynamicallyCompiledAssembly.GetType("Foo.Bar");
var instance = (BaseClass) Activator.CreateInstance(type);
int number = instance.CalculateSomething();
Assert.Equal((int) Math.Sqrt(42), number);
}
}
}
在这个测试中,我首先解析了一段从 netstandard2.0 库中的BaseClass 派生的 C# 代码。这段代码还引用了System.Math。然后,我创建一个 C# 编译对象,其中包括对核心库(.NET Core 2.2)和我的库的引用。此编译对象将 DLL 发送到内存流。如果编译失败,测试将失败,并出现包含所有诊断信息的异常。
此单元测试失败并显示以下错误消息:
(7,31):错误 CS0012:“对象”类型是在未引用的程序集中定义的。您必须添加对程序集 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' 的引用。
(11,26):错误 CS0012:“对象”类型是在未引用的程序集中定义的。您必须添加对程序集 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' 的引用。
我有以下问题:
-
这是否不起作用,因为 Roslyn NuGet 包在 .NET Standard 2.0 项目中被引用,因此总是尝试编译为 netstandard2.0 目标框架名字对象?我怀疑 netstandard2.0 有不同的定义
System.Object转发到目标平台的实际实现。而且我的编译单元没有引用这个转发定义。 -
有没有办法改变目标框架?我看了
CSharpCompilationOptions和EmitOptions,但没有找到让我改变目标框架的任何东西。 - 我是否可能需要使用另一个 Roslyn NuGet 包,例如 Microsoft.Net.Compilers.Toolset? 我尽量避免这种情况,因为实际上我想使用默认编译器而不是 NuGet 包中的编译器。
【问题讨论】:
标签: c# roslyn .net-standard