【发布时间】:2017-03-13 13:42:03
【问题描述】:
我正在尝试动态编译代码并在运行时执行它。所以我以http://www.tugberkugurlu.com/archive/compiling-c-sharp-code-into-memory-and-executing-it-with-roslyn 为指导。
示例中给出的代码运行良好。但是,如果我使用Console.ReadKey(),它会给我错误CS0117: 'Console' does not contain a definition for 'ReadKey'。我在某处读到这是因为 dotnet core 不支持ReadKey ('Console' does not contain a definition for 'ReadKey' in asp.net 5 console App),但我目前正在使用"Microsoft.NETCore.App",如果我在代码中显式使用它而不是在使用 Roslyn 时使用它,Console.ReadKey() 可以完美运行。
- 这是 Roslyn 的问题还是我做错了什么?
-
"Microsoft.NETCore.App"和dotnet core是同一个东西吗?我怀疑我可能正在使用其他东西作为我的目标(这允许我使用ReadKey)和 Roslyn 的 dotnet 核心 - 是否可以将 Roslyn 的目标更改为其他目标?
提前致谢。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace DemoCompiler
{
class Program
{
public static void roslynCompile()
{
string code = @"
using System;
using System.Text;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(string message)
{
Console.WriteLine(message);
Console.ReadKey();
}
}
}";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).GetTypeInfo().Assembly.Location)
};
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
else
{
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
var type= assembly.GetType("RoslynCompileSample.Writer");
var instance = assembly.CreateInstance("RoslynCompileSample.Writer");
var meth = type.GetMember("Write").First() as MethodInfo;
meth.Invoke(instance, new [] {assemblyName});
}
}
}
}
}
编辑:我试图引用System.Console.dll,但我在这和System.Private.CoreLib 之间发生了冲突。我该如何解决?
【问题讨论】:
-
我不是 .NET 核心方面的专家,但考虑到它围绕组件设计的程度,可以很好地猜测
typeof(object)和typeof(Enumerable)不足以引入所有您在主项目中拥有的引用(在 .NET Core 之外,它是 -Console在 .NET 中位于mscorlib中,但不在 .NET Core 中)。特别是,您缺少System.Console.dll,我猜这是罪魁祸首。您需要参考一大堆库来获取默认 C# 项目中的内容:) -
阅读您的评论后,我尝试引用
System.Console.dll。但是,我在两个程序集之间发生了冲突。我猜这是写在这里的一个已知问题github.com/dotnet/roslyn/issues/16211 -
我不会认为这是一个“已知问题”,因为您必须等待我们修复它:人们经常使用“typeof(object).Assembly.Location”模式来初始化编译只是从根本上不会在 .NET Core 世界中工作。这是一种在某些 .NET Framework 方案中恰好可以使用的快捷方式。如果您使用 .NET Core,则需要以其他方式收集内容。
-
@JasonMalinowski 推荐的简单“其他方式”是什么?