无法从源代码在 Roslyn 中创建编译
Cannot create a compilation in Roslyn from source code
出于测试目的,我需要从包含源代码的字符串 source
中获取 System.Reflection.Assembly
。我正在使用罗斯林:
SyntaxTree tree = CSharpSyntaxTree.ParseText(source);
CSharpCompilation compilation = CSharpCompilation.Create("TestCompilation", new[] { tree });
Assembly assembly = null;
using (var stream = new MemoryStream())
{
var emitResult = compilation.Emit(stream);
if (!emitResult.Success)
{
var message = emitResult.Diagnostics.Select(d => d.ToString())
.Aggregate((d1, d2) => $"{d1}{Environment.NewLine}{d2}");
throw new InvalidOperationException($"Errors!{Environment.NewLine}{message}");
}
stream.Seek(0, SeekOrigin.Begin);
assembly = Assembly.Load(stream.ToArray());
}
如您所见,我在这里的尝试是发出一个 CSHarpCompilation
对象,以便稍后可以获取 Assembly
。我正在尝试这样做:
var source = @"
namespace Root.MyNamespace1 {
public class MyClass {
}
}
";
发出错误
但我在 var emitResult = compilation.Emit(stream)
处失败并输入显示错误的条件。我收到 1 个警告和 3 个错误:
- 警告 CS8021:未找到 RuntimeMetadataVersion 的值。未找到包含 System.Object 的程序集,也未找到通过选项指定的 RuntimeMetadataVersion 值。
- (3,34):错误 CS0518:未定义或导入预定义类型 'System.Object'
- (3,34):错误 CS1729:'object' 不包含采用 0 个参数的构造函数
- 错误 CS5001:程序不包含适合入口点的静态'Main'方法
所以我似乎需要添加对 mscorelib
的引用,而且我似乎还需要告诉 Roslyn 我想发出一个 class 库,而不是一个可执行程序集。怎么做?
您缺少对 mscorlib
的元数据引用,您可以通过 CSharpCompilationOptions
更改编译选项。
按如下方式创建您的编译:
var Mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("TestCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib }, options: options);
用于从 not-netstandard 代码 创建一个 netstandard 库(在我的例子中,我从 core3.1 创建了一个 netstandard 库) 代码应该是
var compilation = CSharpCompilation.Create("TestCompilation",
syntaxTrees: new[] {
tree
},
references: new[] {
MetadataReference.CreateFromFile(@"C:\Users\YOURUSERNAME\.nuget\packages\netstandard.library.0.3\build\netstandard2.0\ref\netstandard.dll"
},
options:
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
这里的关键是路径。
由于主机代码是 core3.1,因此不能使用 MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
,因为它引用的是 core3.1 object
而不是 netcore2.0 object
.
当引用一个 nuget 包(现在)将它们下载到 %USERPROFILE%\.nuget\packages
文件夹时,它可以从那里加载。这不适用于任何其他用户,因此必须设计不同的解决方案。可以利用 System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile)
但这可能不适用于 CI/CD.
更新:
System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile)
确实适用于 CI/CD。
MetadataReference.CreateFromFile( Path.Combine(
UserProfilePath, ".nuget", "packages", "netstandard.library", "2.0.3", "build",
"netstandard2.0", "ref", "netstandard.dll"))
查看 LehmanLaidun 个版本。
出于测试目的,我需要从包含源代码的字符串 source
中获取 System.Reflection.Assembly
。我正在使用罗斯林:
SyntaxTree tree = CSharpSyntaxTree.ParseText(source);
CSharpCompilation compilation = CSharpCompilation.Create("TestCompilation", new[] { tree });
Assembly assembly = null;
using (var stream = new MemoryStream())
{
var emitResult = compilation.Emit(stream);
if (!emitResult.Success)
{
var message = emitResult.Diagnostics.Select(d => d.ToString())
.Aggregate((d1, d2) => $"{d1}{Environment.NewLine}{d2}");
throw new InvalidOperationException($"Errors!{Environment.NewLine}{message}");
}
stream.Seek(0, SeekOrigin.Begin);
assembly = Assembly.Load(stream.ToArray());
}
如您所见,我在这里的尝试是发出一个 CSHarpCompilation
对象,以便稍后可以获取 Assembly
。我正在尝试这样做:
var source = @"
namespace Root.MyNamespace1 {
public class MyClass {
}
}
";
发出错误
但我在 var emitResult = compilation.Emit(stream)
处失败并输入显示错误的条件。我收到 1 个警告和 3 个错误:
- 警告 CS8021:未找到 RuntimeMetadataVersion 的值。未找到包含 System.Object 的程序集,也未找到通过选项指定的 RuntimeMetadataVersion 值。
- (3,34):错误 CS0518:未定义或导入预定义类型 'System.Object'
- (3,34):错误 CS1729:'object' 不包含采用 0 个参数的构造函数
- 错误 CS5001:程序不包含适合入口点的静态'Main'方法
所以我似乎需要添加对 mscorelib
的引用,而且我似乎还需要告诉 Roslyn 我想发出一个 class 库,而不是一个可执行程序集。怎么做?
您缺少对 mscorlib
的元数据引用,您可以通过 CSharpCompilationOptions
更改编译选项。
按如下方式创建您的编译:
var Mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("TestCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib }, options: options);
用于从 not-netstandard 代码 创建一个 netstandard 库(在我的例子中,我从 core3.1 创建了一个 netstandard 库) 代码应该是
var compilation = CSharpCompilation.Create("TestCompilation",
syntaxTrees: new[] {
tree
},
references: new[] {
MetadataReference.CreateFromFile(@"C:\Users\YOURUSERNAME\.nuget\packages\netstandard.library.0.3\build\netstandard2.0\ref\netstandard.dll"
},
options:
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
这里的关键是路径。
由于主机代码是 core3.1,因此不能使用 MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
,因为它引用的是 core3.1 object
而不是 netcore2.0 object
.
当引用一个 nuget 包(现在)将它们下载到 %USERPROFILE%\.nuget\packages
文件夹时,它可以从那里加载。这不适用于任何其他用户,因此必须设计不同的解决方案。可以利用 System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile)
但这可能不适用于 CI/CD.
更新:
System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile)
确实适用于 CI/CD。
MetadataReference.CreateFromFile( Path.Combine(
UserProfilePath, ".nuget", "packages", "netstandard.library", "2.0.3", "build",
"netstandard2.0", "ref", "netstandard.dll"))
查看 LehmanLaidun 个版本。