使用 Roslyn 时,控制台不包含 ReadKey 的定义
Console does not contain a definition for ReadKey while using 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
(),但我目前正在使用 "Microsoft.NETCore.App"
,如果我在代码而不是在使用 Roslyn 时。
- 这是 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
之间存在冲突。我该如何解决?
一种方法是将 <PreserveCompilationContext>true</PreserveCompilationContext>
* 添加到您的项目文件,然后使用 Microsoft.Extensions.DependencyModel.DependencyContext
获取当前项目的所有引用程序集:
var references = DependencyContext.Default.CompileLibraries
.SelectMany(l => l.ResolveReferencePaths())
.Select(l => MetadataReference.CreateFromFile(l));
这似乎可以避免您遇到的错误,但会导致如下警告:
warning CS1701: Assuming assembly reference 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' used by 'System.Console' matches identity 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' of 'System.Runtime', you may need to supply runtime policy
As far as I can tell, this should not be an issue.
* 这假设您使用的是 csproj/VS2017。如果你还在项目中。json/VS2015,同样可以使用 "buildOptions": { "preserveCompilationContext": true }
。
在 https://github.com/dotnet/roslyn/issues/13267 找到了类似的问题和解决方案。
I have got around this (as far as I can tell) by:
Copying System.Runtime.dll
and System.Runtime.Extensions.dll
from:
C:\Users\<user>\.nuget\packages\System.Runtime.1.0\ref\netstandard1.5
and putting them in a References folder in my project. So then instead of referencing mscorlib.dll
and System.Private.CoreLib.dll
I reference these
我试过了,发现仅引用 System.Runtime.dll
就足够了(至少在我的情况下)。明确一点,我现在使用 MetadataReference.CreateFromFile("System.Runtime.dll")
而不是 MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location)
,它直接引用工作目录中存在的 DLL。
唯一的缺点是我必须将 dll 与我的项目一起分发,但这没关系,因为我现在可以在 .net 核心上正确使用 Roslyn,而不是将基本框架更改为完整的 .net
我正在尝试动态编译代码并在运行时执行它。所以我以 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
("Microsoft.NETCore.App"
,如果我在代码而不是在使用 Roslyn 时。
- 这是 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
之间存在冲突。我该如何解决?
一种方法是将 <PreserveCompilationContext>true</PreserveCompilationContext>
* 添加到您的项目文件,然后使用 Microsoft.Extensions.DependencyModel.DependencyContext
获取当前项目的所有引用程序集:
var references = DependencyContext.Default.CompileLibraries
.SelectMany(l => l.ResolveReferencePaths())
.Select(l => MetadataReference.CreateFromFile(l));
这似乎可以避免您遇到的错误,但会导致如下警告:
warning CS1701: Assuming assembly reference 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' used by 'System.Console' matches identity 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' of 'System.Runtime', you may need to supply runtime policy
As far as I can tell, this should not be an issue.
* 这假设您使用的是 csproj/VS2017。如果你还在项目中。json/VS2015,同样可以使用 "buildOptions": { "preserveCompilationContext": true }
。
在 https://github.com/dotnet/roslyn/issues/13267 找到了类似的问题和解决方案。
I have got around this (as far as I can tell) by:
Copying
System.Runtime.dll
andSystem.Runtime.Extensions.dll
from:C:\Users\<user>\.nuget\packages\System.Runtime.1.0\ref\netstandard1.5
and putting them in a References folder in my project. So then instead of referencingmscorlib.dll
andSystem.Private.CoreLib.dll
I reference these
我试过了,发现仅引用 System.Runtime.dll
就足够了(至少在我的情况下)。明确一点,我现在使用 MetadataReference.CreateFromFile("System.Runtime.dll")
而不是 MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location)
,它直接引用工作目录中存在的 DLL。
唯一的缺点是我必须将 dll 与我的项目一起分发,但这没关系,因为我现在可以在 .net 核心上正确使用 Roslyn,而不是将基本框架更改为完整的 .net