[英]Use Roslyn in NetStandard2.0 project to compile dynamically created code
I'm trying to create a reusable .NET Standard 2.0 library that uses Roslyn to dynamically compile code at runtime to an in-memory assembly.我正在尝试创建一个可重用的 .NET 标准 2.0 库,该库使用 Roslyn 在运行时将代码动态编译为内存中的程序集。 This dynamically created assembly contains classes that derive from a base class that is part of the library.
这个动态创建的程序集包含派生自作为库一部分的基础 class 的类。 I instantiate them via reflection in the apps that reference the library.
我通过引用库的应用程序中的反射来实例化它们。 The project structure looks like this:
项目结构如下所示:
Suppose that I have the following type in my netstandard2.0 library:假设我的 netstandard2.0 库中有以下类型:
namespace MyLibrary
{
public abstract class BaseClass
{
public abstract int CalculateSomething();
}
}
I then create the following unit test in a .NET Core 2.2 project:然后我在 .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);
}
}
}
In this test, I first parse a piece of C# code that derives from BaseClass
in the netstandard2.0 library.在这个测试中,我首先解析了一段 C# 代码,它来自 netstandard2.0 库中的
BaseClass
。 This piece of code additionally references System.Math
.这段代码还引用了
System.Math
。 I then create a C# compilation object that includes references to the core lib (of .NET Core 2.2) and my library.然后,我创建了一个 C# 编译 object,其中包括对核心库(.NET Core 2.2)和我的库的引用。 This compilation object emits the DLL to a memory stream.
此编译 object 将 DLL 发射到 memory ZF7B44CFAFD5C52223D5498196C8A2E If compiling fails, the test will fail with an exception that contains all diagnostics.
如果编译失败,则测试将失败,并出现包含所有诊断信息的异常。
This unit test does fail with the following error message:此单元测试确实失败并显示以下错误消息:
(7,31): error CS0012: The type 'Object' is defined in an assembly that is not referenced. (7,31):错误 CS0012:“对象”类型是在未引用的程序集中定义的。 You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
您必须添加对程序集“netstandard,Version=2.0.0.0,Culture=neutral,PublicKeyToken=cc7b13ffcd2ddd51”的引用。
(11,26): error CS0012: The type 'Object' is defined in an assembly that is not referenced. (11,26):错误 CS0012:“对象”类型是在未引用的程序集中定义的。 You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
您必须添加对程序集“netstandard,Version=2.0.0.0,Culture=neutral,PublicKeyToken=cc7b13ffcd2ddd51”的引用。
I have the following questions:我有以下问题:
System.Object
that forwards to the actual implementation of the target platform.System.Object
的定义不同,它转发到目标平台的实际实现。 And this forwarding definition is not referenced in my compilation unit.CSharpCompilationOptions
and EmitOptions
, but couldn't find anything that let's me change the target framework.CSharpCompilationOptions
和EmitOptions
,但找不到任何可以让我更改目标框架的内容。BaseClass
, targets .netstandard2.0
(it means that this library references netstandard.dll 2.0
) and this assumes that your library, which references library with BaseClass
, should have a reference to netstandard.dll 2.0
to correctrly resolve all corresponding types.BaseClass
的库以.netstandard2.0
为目标(这意味着该库引用netstandard.dll 2.0
)并且这假定您的库引用带有BaseClass
的库应该引用netstandard.dll 2.0
正确解析所有相应的类型。 So you should add reference on them (the netstandard.dll
for .net47
or the similar .netstandard.dll
for .netcore2.2
).netstandard.dll
用于.net47
或类似的.netstandard.dll
用于.netcore2.2
)。 (By the way, when you reference .netstandard2.0
from .net47
library you probably should add a couple of additional libraries as reference from path_to_visual_studio\MSBuild\Microsoft\Microsoft.NET.Build.Extensions
) .net47
库中引用.netstandard2.0
时,您可能应该添加几个额外的库作为path_to_visual_studio\MSBuild\Microsoft\Microsoft.NET.Build.Extensions
的引用)Compilation
doesn't know anything about target framework and it should not know anything about it. Compilation
对目标框架一无所知,也不应该对此一无所知。 Compilation
works with trees and references (and with some options and metadata of references of course), so you should manually append references that will be required in compilation. Compilation
适用于树和引用(当然还有一些选项和引用的元数据),因此您应该手动 append 引用,编译中需要这些引用。 (By the way, if you have a csproj
or a sln
file you may use MsBuildWorkspace
that allow to get a ready compilation from the project or solution file, in the most of cases) csproj
或sln
文件,你可以使用MsBuildWorkspace
允许从项目或解决方案文件中获取准备好的编译,在大多数情况下)Compilation
by hand if you know or can find out all references that will be required in compilation, else try to use Microsoft.CodeAnalysis.Workspaces.MSBuild to analyze .csproj
or .sln
files and then retrieve Compilation
from them.Compilation
,否则尝试使用Microsoft.CodeAnalysis.Workspaces.MSBuild分析.csproj
或.sln
文件,然后从中检索Compilation
。 Microsoft.Net.Compilers.Toolset
just gives to you possibility to compile your project by compilers not are installed on your system, but are contained in this package. Microsoft.Net.Compilers.Toolset
只是让您有可能通过未安装在您的系统上但包含在此 package 中的编译器来编译您的项目。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.