使用Roslyn时,控制台不包含ReadKey的定义

时间:2017-03-13 13:42:04

标签: c# .net-core roslyn

我正在尝试动态编译代码并在运行时执行它。所以我按照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。

  • 这是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之间存在冲突。我该如何解决?

2 个答案:

答案 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.dllSystem.Runtime.Extensions.dll:   C:\Users\<user>\.nuget\packages\System.Runtime\4.1.0\ref\netstandard1.5   并将它们放在我的项目的References文件夹中。那么我不是引用mscorlib.dllSystem.Private.CoreLib.dll而是引用这些

我试过这个并发现只引用System.Runtime.dll就足够了(至少在我的情况下)。为了清楚起见,我现在使用MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location)而不是MetadataReference.CreateFromFile("System.Runtime.dll"),它直接引用工作目录中的DLL。

唯一的缺点是我必须将dll与我的项目一起分发,但考虑到我现在可以在.net核心上正确使用Roslyn而不是将基本框架更改为完整.net