![](/img/trans.png)
[英]System.PlatformNotSupportedException AesCryptoServiceProvider
[英]System.PlatformNotSupportedException Compiling C# code at runtime .NET Core
尝试在运行时在 .NET Core 上编译简单的 C# 代码,但出现此错误:
System.PlatformNotSupportedException:“此平台不支持操作。”
在这条线上:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
我的代码:
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ @"
}
}
}
";
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = true;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
main.Invoke(null, null);
我推荐使用 Roslyn 编译器。 您需要添加引用 Microsoft.CodeAnalysis 和 Microsoft.CodeAnalysis.CSharp 才能使以下示例正常工作。 请注意, RoslynCompiler
class 会动态加载程序集。 如果要将编译保存到磁盘以供重用,您可以相当轻松地修改 class 以使用FileStream
而不是MemoryStream
。
RoslynCompiler Class 的示例用法(下)
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
Console.WriteLine(\"Hello, world!\");
}
public static void WithParams(string message)
{
Console.WriteLine(message);
}
}
}
";
var compiler = new RoslynCompiler("First.Program", code, new[] {typeof(Console)});
var type = compiler.Compile();
type.GetMethod("Main").Invoke(null, null);
//result: Hellow World!
// pass an object array to the second null parameter to pass arguments
type.GetMethod("WithParams").Invoke(null, new object[] {"Hi there from invoke!"});
//result: Hi from invoke
Roslyn 编译器 Class(快速而肮脏的示例)
public class RoslynCompiler
{
readonly CSharpCompilation _compilation;
Assembly _generatedAssembly;
Type? _proxyType;
string _assemblyName;
string _typeName;
public RoslynCompiler(string typeName, string code, Type[] typesToReference)
{
_typeName = typeName;
var refs = typesToReference.Select(h => MetadataReference.CreateFromFile(h.Assembly.Location) as MetadataReference).ToList();
//some default refeerences
refs.Add(MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")));
refs.Add(MetadataReference.CreateFromFile(typeof(Object).Assembly.Location));
//generate syntax tree from code and config compilation options
var syntax = CSharpSyntaxTree.ParseText(code);
var options = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
allowUnsafe: true,
optimizationLevel: OptimizationLevel.Release);
_compilation = CSharpCompilation.Create(_assemblyName = Guid.NewGuid().ToString(), new List<SyntaxTree> { syntax }, refs, options);
}
public Type Compile()
{
if (_proxyType != null) return _proxyType;
using (var ms = new MemoryStream())
{
var result = _compilation.Emit(ms);
if (!result.Success)
{
var compilationErrors = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error)
.ToList();
if (compilationErrors.Any())
{
var firstError = compilationErrors.First();
var errorNumber = firstError.Id;
var errorDescription = firstError.GetMessage();
var firstErrorMessage = $"{errorNumber}: {errorDescription};";
var exception = new Exception($"Compilation failed, first error is: {firstErrorMessage}");
compilationErrors.ForEach(e => { if (!exception.Data.Contains(e.Id)) exception.Data.Add(e.Id, e.GetMessage()); });
throw exception;
}
}
ms.Seek(0, SeekOrigin.Begin);
_generatedAssembly = AssemblyLoadContext.Default.LoadFromStream(ms);
_proxyType = _generatedAssembly.GetType(_typeName);
return _proxyType;
}
}
}
性能提示
如果性能很重要,请使用委托而不是Invoke
,如下所示以实现接近预编译的吞吐量:
void Main()
{
string code = @"OMITTED EXAMPLE CODE FROM SAMPLE ABOVE";
var compiler = new RoslynCompiler("First.Program", code, new[] { typeof(Console) });
var type = compiler.Compile();
// If perf matters used delegates to get near pre-compiled througput vs Invoke()
var cachedDelegate = new DynamicDelegateCacheExample(type);
cachedDelegate.Main();
//result: Hellow world!
cachedDelegate.Main("Hi there from cached delegate!");
//result: Hi there from cached delegate!
}
public class DynamicDelegateCacheExample
{
delegate void methodNoParams();
delegate void methodWithParamas(string message);
private static methodNoParams cachedDelegate;
private static methodWithParamas cachedDelegateWeithParams;
public DynamicDelegateCacheExample(Type myDynamicType)
{
cachedDelegate = myDynamicType.GetMethod("Main").CreateDelegate<methodNoParams>();
cachedDelegateWeithParams = myDynamicType.GetMethod("WithParams").CreateDelegate<methodWithParamas>();
}
public void Main() => cachedDelegate();
public void Main(string message) => cachedDelegateWeithParams(message);
}
使用 .net 核心网络标准并发布到一个独立的 exe,您还需要一些技巧;
public static ModuleMetadata GetMetadata(this Assembly assembly)
{
// based on https://github.com/dotnet/runtime/issues/36590#issuecomment-689883856
unsafe
{
return assembly.TryGetRawMetadata(out var blob, out var len)
? ModuleMetadata.CreateFromMetadata((IntPtr)blob, len)
: throw new InvalidOperationException($"Could not get metadata from {assembly.FullName}");
}
}
#pragma warning disable IL3000
public static MetadataReference GetReference(this Assembly assembly)
=> (assembly.Location == "")
? AssemblyMetadata.Create(assembly.GetMetadata()).GetReference()
: MetadataReference.CreateFromFile(assembly.Location);
#pragma warning restore IL3000
public static Assembly Compile(string source, IEnumerable<Type> references)
{
var refs = new HashSet<Assembly>(){
typeof(object).Assembly
};
foreach (var t in references)
refs.Add(t.Assembly);
foreach (var a in AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic
&& a.ExportedTypes.Count() == 0
&& (a.FullName.Contains("netstandard") || a.FullName.Contains("System.Runtime,"))))
refs.Add(a);
var options = CSharpParseOptions.Default
.WithLanguageVersion(LanguageVersion.Latest);
var compileOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
var compilation = CSharpCompilation.Create("Dynamic",
new[] { SyntaxFactory.ParseSyntaxTree(source, options) },
refs.Select(a => a.GetReference()),
compileOptions
);
using var ms = new MemoryStream();
var e = compilation.Emit(ms);
if (!e.Success)
throw new Exception("Compilation failed");
ms.Seek(0, SeekOrigin.Begin);
var context = new AssemblyLoadContext(null, true);
return context.LoadFromStream(ms);
}
// for dynamically implementing some interface;
public static C CompileInstance<C>(string source, IEnumerable<Type> references)
{
var assembly = Compile(source, references);
var modelType = assembly.DefinedTypes.Where(t => typeof(C).IsAssignableFrom(t)).Single();
return (C)Activator.CreateInstance(modelType);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.