我正在尝试动态编译代码并在运行时执行它。所以我按照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核心不支持ReadKey
('Console' does not contain a definition for 'ReadKey' in asp.net 5 console App),但我目前正在使用"Microsoft.NETCore.App"
,而Console.ReadKey()
如果我在代码而不是使用Roslyn。
"Microsoft.NETCore.App"
和dotnet core
是一回事吗?我怀疑我可能会使用其他东西作为我的目标(这允许我使用ReadKey
)和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
之间存在冲突。我该如何解决?
答案 0 :(得分:0)
一种方法是将<PreserveCompilationContext>true</PreserveCompilationContext>
*添加到项目文件中,然后使用Microsoft.Extensions.DependencyModel.DependencyContext
获取当前项目的所有参考程序集:
var references = DependencyContext.Default.CompileLibraries
.SelectMany(l => l.ResolveReferencePaths())
.Select(l => MetadataReference.CreateFromFile(l));
这似乎可以避免你得到的错误,但会导致警告:
警告CS1701:假设程序集引用&System; Run.Runtime,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a&#39;由System.Console&#39;使用匹配身份&#39; System.Runtime,Version = 4.1.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a&#39;在System.Runtime&#39;中,您可能需要提供运行时策略
As far as I can tell, this should not be an issue.
*这假设你正在使用csproj / VS2017。如果您仍在使用project.json / VS2015,则可以使用"buildOptions": { "preserveCompilationContext": true }
完成相同操作。
答案 1 :(得分:0)
在Sass处找到与解决方案类似的问题。
我已经解决了这个问题(据我所知):
从以下位置复制
System.Runtime.dll
和System.Runtime.Extensions.dll
:C:\Users\<user>\.nuget\packages\System.Runtime\4.1.0\ref\netstandard1.5
并将它们放在我的项目的References文件夹中。那么我不是引用mscorlib.dll
和System.Private.CoreLib.dll
而是引用这些
我试过这个并发现只引用System.Runtime.dll
就足够了(至少在我的情况下)。为了清楚起见,我现在使用MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location)
而不是MetadataReference.CreateFromFile("System.Runtime.dll")
,它直接引用工作目录中的DLL。
唯一的缺点是我必须将dll与我的项目一起分发,但考虑到我现在可以在.net核心上正确使用Roslyn而不是将基本框架更改为完整.net