C# 在NetStandard2.0项目中使用Roslyn编译动态创建的代码
我正在尝试创建一个可重用的.NET标准2.0库,它使用Roslyn在运行时将代码动态编译到内存中的程序集。此动态创建的程序集包含从作为库一部分的基类派生的类。我通过引用库的应用程序中的反射来实例化它们。项目结构如下所示: 假设我的netstandard2.0库中有以下类型:C# 在NetStandard2.0项目中使用Roslyn编译动态创建的代码,c#,roslyn,.net-standard,C#,Roslyn,.net Standard,我正在尝试创建一个可重用的.NET标准2.0库,它使用Roslyn在运行时将代码动态编译到内存中的程序集。此动态创建的程序集包含从作为库一部分的基类派生的类。我通过引用库的应用程序中的反射来实例化它们。项目结构如下所示: 假设我的netstandard2.0库中有以下类型: 名称空间MyLibrary { 公共抽象类基类 { 公共摘要int calculateMething(); } } 然后,我在.NET Core 2.2项目中创建以下单元测试: namespace NetCore2\u
名称空间MyLibrary
{
公共抽象类基类
{
公共摘要int calculateMething();
}
}
然后,我在.NET Core 2.2项目中创建以下单元测试:
namespace NetCore2\u 2.Tests
{
公共静态类测试
{
[事实]
public static void compiled dynamicallyandinvoke()
{
//使用简单类创建语法树
var syntaxTree=CSharpSyntaxTree.ParseText(@)
使用制度;
使用我的图书馆;
名称空间Foo
{
公共密封类栏:基类
{
公共覆盖int CalculateMething()
{
返回(int)数学Sqrt(42);
}
}
}");
//创建编译,包括语法树和对核心库的引用
var compilation=csharpcomilation.Create(
“MyDynamicsSembly.dll”,
新[]{syntaxTree},
新[]
{
MetadataReference.CreateFromFile(typeof(object.Assembly.Location),
MetadataReference.CreateFromFile(typeof(BaseClass.Assembly.Location)
},
新的CSharp编译选项(
OutputKind.DynamicallyLinkedLibrary,
optimizationLevel:optimizationLevel.Release)
);
//将其编译为内存流
var memoryStream=新的memoryStream();
var result=compilation.Emit(memoryStream);
//如果未成功,则抛出异常以使测试失败
如果(!result.Success)
{
var stringBuilder=新的stringBuilder();
foreach(结果中的var诊断。诊断)
{
AppendLine(diagnostic.ToString());
}
抛出新的XunitException(stringBuilder.ToString());
}
//否则,加载程序集,通过反射实例化类型并调用CalculateMething
var dynamicallyCompiledAssembly=Assembly.Load(memoryStream.ToArray());
var type=dynamicallyCompiledAssembly.GetType(“Foo.Bar”);
var instance=(基类)Activator.CreateInstance(类型);
int number=instance.calculateMething();
Assert.Equal((int)Math.Sqrt(42),number);
}
}
}
在这个测试中,我首先解析一段C代码,它来自netstandard2.0库中的BaseClass
。这段代码还引用了System.Math
。然后,我创建一个C#编译对象,其中包含对核心库(位于.NETCore2.2中)和我的库的引用。此编译对象将DLL发送到内存流。如果编译失败,测试将失败,出现包含所有诊断的异常
此单元测试失败,并显示以下错误消息:
(7,31):错误CS0012:在未引用的程序集中定义了类型“Object”。必须添加对程序集“netstandard,Version=2.0.0.0,Culture=neutral,PublicKeyToken=CC7B13FFCD2DD51”的引用
(11,26):错误CS0012:在未引用的程序集中定义了类型“Object”。必须添加对程序集“netstandard,Version=2.0.0.0,Culture=neutral,PublicKeyToken=CC7B13FFCD2DD51”的引用
我有以下问题:
- 这是否不起作用,因为Roslyn NuGet包在.NET标准2.0项目中被引用,因此总是试图编译到netstandard2.0目标框架名字对象?我怀疑netstandard2.0对转发到目标的实际实现的
有不同的定义站台。我的编译单元中没有引用此转发定义System.Object
- 有办法更改目标框架吗?我查看了
和csharpcomilationoptions
,但找不到任何让我更改目标框架的方法EmitOptions
- 我是否需要使用另一个Roslyn NuGet软件包,例如?我尽量避免这样做,因为我实际上希望使用默认编译器,而不是NuGet软件包中的编译器
- 它不起作用,因为包含
基类的库面向
(这意味着此库引用.netstandard2.0
),这假设您的库引用了netstandard.dll 2.0
基类的库,应参考
,以正确解析所有相应的类型。因此,您应该添加对它们的引用(对于netstandard.dll 2.0
的.net47
,或者对于netstandard.dll
的类似.netcore2.2
)。 (顺便说一句,当您从.netstandard.dll
库中引用.net47
时,您可能应该添加两个附加库,作为从.netstandard2.0
的引用)路径\u到\u visual\u studio\MSBuild\Microsoft\Microsoft.NET.Build.Extensions
- Roslyn
对目标框架一无所知,也不应该知道任何东西<代码>编译使用树和引用(当然还有一些选项和引用的元数据),因此您应该手动附加编译中需要的引用。(顺便说一下,如果您有编译
或csproj