Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在NetStandard2.0项目中使用Roslyn编译动态创建的代码_C#_Roslyn_.net Standard - Fatal编程技术网

C# 在NetStandard2.0项目中使用Roslyn编译动态创建的代码

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

我正在尝试创建一个可重用的.NET标准2.0库,它使用Roslyn在运行时将代码动态编译到内存中的程序集。此动态创建的程序集包含从作为库一部分的基类派生的类。我通过引用库的应用程序中的反射来实例化它们。项目结构如下所示:

假设我的netstandard2.0库中有以下类型:

名称空间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