C# EmitResult=compilation.Emit(毫秒); 如果(!result.Success) { //处理异常 IEnumerable failures=result.Diagnostics.Where(Diagnostics=> 诊断性.IsWarningAsError | | 诊断严重性==诊断严重性错误); foreach(故障诊断) { WriteLine(“{0}:{1}”,diagnostic.Id,diagnostic.GetMessage()); } } 其他的 { //加载此“虚拟”DLL以便我们可以使用 Seek女士(0,SeekOrigin.Begin); Assembly=Assembly.Load(ms.ToArray()); //创建所需类的实例并调用所需函数 Type Type=assembly.GetType(“RoslynCompileSample.Writer”); object obj=Activator.CreateInstance(类型); 键入.InvokeMember(“写入”, BindingFlags.Default | BindingFlags.InvokeMethod, 无效的 obj, 新对象[]{“Hello World”}); } } Console.ReadLine(); } } }
发现这很有用-确保编译后的程序集引用您当前引用的所有内容,因为您很有可能希望正在编译的C使用发出以下信息的代码中的某些类等: (字符串C# EmitResult=compilation.Emit(毫秒); 如果(!result.Success) { //处理异常 IEnumerable failures=result.Diagnostics.Where(Diagnostics=> 诊断性.IsWarningAsError | | 诊断严重性==诊断严重性错误); foreach(故障诊断) { WriteLine(“{0}:{1}”,diagnostic.Id,diagnostic.GetMessage()); } } 其他的 { //加载此“虚拟”DLL以便我们可以使用 Seek女士(0,SeekOrigin.Begin); Assembly=Assembly.Load(ms.ToArray()); //创建所需类的实例并调用所需函数 Type Type=assembly.GetType(“RoslynCompileSample.Writer”); object obj=Activator.CreateInstance(类型); 键入.InvokeMember(“写入”, BindingFlags.Default | BindingFlags.InvokeMethod, 无效的 obj, 新对象[]{“Hello World”}); } } Console.ReadLine(); } } },c#,C#,发现这很有用-确保编译后的程序集引用您当前引用的所有内容,因为您很有可能希望正在编译的C使用发出以下信息的代码中的某些类等: (字符串code是正在编译的动态C) 在我的例子中,我发出了一个类,其名称存储在一个字符串中,className,它有一个名为Get(),返回类型为storydataid。下面是调用该方法的过程: var tempType = asm.GetType(className); var ids = (StoryDataIds)tempType.
code
是正在编译的动态C)
在我的例子中,我发出了一个类,其名称存储在一个字符串中,className
,它有一个名为Get()
,返回类型为storydataid
。下面是调用该方法的过程:
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
警告:编译速度可能非常慢,令人惊讶。在我们相对快速的服务器上,一小段相对简单的10行代码以正常优先级在2-10秒内编译完成。决不能将对
CompileAssemblyFromSource()
的调用与具有正常性能预期的任何对象(如web请求)绑定在一起。相反,在低优先级线程上主动编译您需要的代码,并有一种处理代码的方法,该方法要求代码准备就绪,直到有机会完成编译。例如,您可以在批处理作业流程中使用它。我最近需要生成用于单元测试的流程。这篇文章很有用,因为我创建了一个简单的类,可以使用字符串形式的代码或项目中的代码来实现这一点。要构建这个类,您需要ICSharpCode.Decompiler
和Microsoft.codesanalysis
NuGet包。下面是课程:
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
public static class CSharpRunner
{
public static object Run(string snippet, IEnumerable<Assembly> references, string typeName, string methodName, params object[] args) =>
Invoke(Compile(Parse(snippet), references), typeName, methodName, args);
public static object Run(MethodInfo methodInfo, params object[] args)
{
var refs = methodInfo.DeclaringType.Assembly.GetReferencedAssemblies().Select(n => Assembly.Load(n));
return Invoke(Compile(Decompile(methodInfo), refs), methodInfo.DeclaringType.FullName, methodInfo.Name, args);
}
private static Assembly Compile(SyntaxTree syntaxTree, IEnumerable<Assembly> references = null)
{
if (references is null) references = new[] { typeof(object).Assembly, typeof(Enumerable).Assembly };
var mrefs = references.Select(a => MetadataReference.CreateFromFile(a.Location));
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
else
{
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
}
}
}
private static SyntaxTree Decompile(MethodInfo methodInfo)
{
var decompiler = new CSharpDecompiler(methodInfo.DeclaringType.Assembly.Location, new DecompilerSettings());
var typeInfo = decompiler.TypeSystem.MainModule.Compilation.FindType(methodInfo.DeclaringType).GetDefinition();
return Parse(decompiler.DecompileTypeAsString(typeInfo.FullTypeName));
}
private static object Invoke(Assembly assembly, string typeName, string methodName, object[] args)
{
var type = assembly.GetType(typeName);
var obj = Activator.CreateInstance(type);
return type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, args);
}
private static SyntaxTree Parse(string snippet) => CSharpSyntaxTree.ParseText(snippet);
}
是的,CodeDOM的好处是它可以在内存中为您生成程序集(以及以易于阅读的格式提供错误消息和其他信息)。@Noldorin,C#CodeDOM实现实际上不会在内存中生成程序集。您可以为它启用标志,但它会被忽略。它使用了一个临时文件。@Matt:是的,很好,我忘了那个事实。尽管如此,它仍然大大简化了流程(使其有效地显示为程序集是在内存中生成的),并提供了一个完整的托管接口,这比处理流程要好得多。此外,CodeDomProvider只是一个调用csc.exe的类。尽管我怀疑您是否使用Mono,我认为有必要指出存在一个Mono.CSharp名称空间(),它实际上包含一个编译器作为服务,这样您就可以以最小的麻烦动态地内联运行基本代码/计算表达式。一般来说,我对编程很在行,我认为这很酷,但我想不出你为什么想要/这会有用。谢谢你的解释。@Crash893:几乎任何类型的设计器应用程序的脚本系统都可以很好地利用它。当然,也有诸如IronPythonLua之类的替代方案,但这肯定是其中之一。请注意,通过公开接口和加载包含接口实现的编译DLL,而不是直接加载代码,插件系统的开发会更好。我一直认为“CodeDom”是让我使用DOM(文档对象模型)创建代码文件的东西。在System.CodeDom中,有一些对象可以表示代码包含的所有构件—类的对象、接口的对象、构造函数的对象、语句、属性、字段等。然后,我可以使用该对象模型构造代码。这个答案中显示的是在程序中编译代码文件。不是CodeDom,尽管与CodeDom类似,它动态地生成一个程序集。类比:我可以使用DOM或字符串concats创建HTML页面。这里有一篇文章展示了CodeDom的作用:这是一个有价值的、有用的视角。C#编译器使用的代码与C#编译器使用的代码相同,这是最大的好处。复杂是一个相对的术语,但无论如何,在运行时编译代码是一项复杂的工作。然而,上面的代码一点也不复杂。我知道这篇文章已经有几年的历史了,但我认为值得一提的是,随着介绍,动态编译原始C#并在.NET程序中运行它的能力只是简单了一点。您的答案是独一无二的。其他人无法解决我的问题。将当前运行代码中的所有引用程序集都提供给正在编译的程序集是一个好主意。我必须使用compilerParams.ReferencedAssembly.Add()为编译后的程序集提供更多的引用程序集。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace RoslynCompileSample
{
class Program
{
static void Main(string[] args)
{
// define source code, then parse it (to the type used for compilation)
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
using System;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
}");
// define other necessary objects for compilation
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
// analyse and generate IL code from syntax tree
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
// write IL code into memory
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
// handle exceptions
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
{
// load this 'virtual' DLL so that we can use
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
// create instance of the desired class and call the desired function
Type type = assembly.GetType("RoslynCompileSample.Writer");
object obj = Activator.CreateInstance(type);
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] { "Hello World" });
}
}
Console.ReadLine();
}
}
}
var refs = AppDomain.CurrentDomain.GetAssemblies();
var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
compileParams.GenerateInMemory = true;
compileParams.GenerateExecutable = false;
var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
var asm = compilerResult.CompiledAssembly;
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
public static class CSharpRunner
{
public static object Run(string snippet, IEnumerable<Assembly> references, string typeName, string methodName, params object[] args) =>
Invoke(Compile(Parse(snippet), references), typeName, methodName, args);
public static object Run(MethodInfo methodInfo, params object[] args)
{
var refs = methodInfo.DeclaringType.Assembly.GetReferencedAssemblies().Select(n => Assembly.Load(n));
return Invoke(Compile(Decompile(methodInfo), refs), methodInfo.DeclaringType.FullName, methodInfo.Name, args);
}
private static Assembly Compile(SyntaxTree syntaxTree, IEnumerable<Assembly> references = null)
{
if (references is null) references = new[] { typeof(object).Assembly, typeof(Enumerable).Assembly };
var mrefs = references.Select(a => MetadataReference.CreateFromFile(a.Location));
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
else
{
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
}
}
}
private static SyntaxTree Decompile(MethodInfo methodInfo)
{
var decompiler = new CSharpDecompiler(methodInfo.DeclaringType.Assembly.Location, new DecompilerSettings());
var typeInfo = decompiler.TypeSystem.MainModule.Compilation.FindType(methodInfo.DeclaringType).GetDefinition();
return Parse(decompiler.DecompileTypeAsString(typeInfo.FullTypeName));
}
private static object Invoke(Assembly assembly, string typeName, string methodName, object[] args)
{
var type = assembly.GetType(typeName);
var obj = Activator.CreateInstance(type);
return type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, args);
}
private static SyntaxTree Parse(string snippet) => CSharpSyntaxTree.ParseText(snippet);
}
void Demo1()
{
const string code = @"
public class Runner
{
public void Run() { System.IO.File.AppendAllText(@""C:\Temp\NUnitTest.txt"", System.DateTime.Now.ToString(""o"") + ""\n""); }
}";
CSharpRunner.Run(code, null, "Runner", "Run");
}
void Demo2()
{
CSharpRunner.Run(typeof(Runner).GetMethod("Run"));
}
public class Runner
{
public void Run() { System.IO.File.AppendAllText(@"C:\Temp\NUnitTest.txt", System.DateTime.Now.ToString("o") + "\n"); }
}