public static IExecutionContext Compile(ExpressionFeatures features, string expression, string[] parameterNames, AppDomain domain = null) { string expressionLine = $"{{{{ '{expression}' | inline_functions | clean }}}}"; StringBuilder sb = new StringBuilder(); sb.AppendLine($"namespace Expressions"); sb.AppendLine($"{{"); sb.AppendLine($" public static class Expression"); sb.AppendLine($" {{"); EmitMethodSignatures(features, sb, expressionLine, parameterNames); sb.AppendLine($" }}"); sb.AppendLine($"}}"); string source = sb.ToString(); Template template = Template.Parse(source); string code = template.Render(Hash.FromAnonymousObject(new { expression })); // Note: GenerateInMemory still creates an assembly on disk! CompilerParameters p = new CompilerParameters { WarningLevel = 4, GenerateExecutable = false, GenerateInMemory = domain == null, CompilerOptions = "/optimize" }; if (features.HasFlag(ExpressionFeatures.UseDynamic)) { p.ReferencedAssemblies.Add("Microsoft.CSharp.dll"); p.ReferencedAssemblies.Add("System.Core.dll"); } CodeDomProvider compiler = new CSharpCodeProvider(); CompilerResults r = compiler.CompileAssemblyFromSource(p, code); // load into AppDomain.Current if (domain == null || domain == AppDomain.CurrentDomain) { return(new LocalExecutor(r.CompiledAssembly)); } // load assembly into another app domain (without leaking into this one) RemoteExecutor remote = (RemoteExecutor)domain.CreateInstanceAndUnwrap(typeof(RemoteExecutor).Assembly.FullName, typeof(RemoteExecutor).FullName); remote.LoadFrom(r.PathToAssembly); return(remote); }
public static IExecutionContext Compile(string expression, string[] parameterNames, TraceSource trace, ExpressionFeatures features, string @namespace = "MyNamespace", AppDomain domain = null) { const string ls = "{{"; const string le = "}}"; string expressionLine = $"{ls}expression{le}"; StringBuilder sb = new StringBuilder(); sb.AppendLine($"using System.ComponentModel;"); sb.AppendLine(); sb.AppendLine($"namespace {@namespace}"); sb.AppendLine($"{{"); sb.AppendLine($" [Description(\"{expression}\")]"); sb.AppendLine($" public static class Expression"); sb.AppendLine($" {{"); EmitMethodSignatures(features, sb, expressionLine, parameterNames, trace); sb.AppendLine($" }}"); sb.AppendLine($"}}"); string source = sb.ToString(); Template template = Template.Parse(source); string code = template.Render(Hash.FromAnonymousObject(new { expression })); trace?.TraceInformation($"Compiling expression: {expression}"); trace?.TraceInformation(code); trace?.Flush(); // Note: GenerateInMemory still creates an assembly on disk! CompilerParameters p = new CompilerParameters { WarningLevel = 4, GenerateExecutable = false, GenerateInMemory = domain == null, CompilerOptions = "/optimize" }; p.ReferencedAssemblies.Add(typeof(DescriptionAttribute).Assembly.Location); if (features.HasFlag(ExpressionFeatures.UseDynamicBinding)) { p.ReferencedAssemblies.Add(typeof(DynamicAttribute).Assembly.Location); p.ReferencedAssemblies.Add(typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly.Location); } CodeDomProvider compiler = new CSharpCodeProvider(); CompilerResults r = compiler.CompileAssemblyFromSource(p, code); if (r.Errors.Count > 0) { trace?.TraceEvent(TraceEventType.Error, 500, "Compiler errors encountered"); foreach (CompilerError error in r.Errors.OfType <CompilerError>().Where(e => e.IsWarning)) { trace?.TraceEvent(TraceEventType.Warning, 500, error.ToString()); } foreach (CompilerError error in r.Errors.OfType <CompilerError>().Where(e => !e.IsWarning)) { trace?.TraceEvent(TraceEventType.Error, 500, error.ToString()); } } // load into AppDomain.Current if (domain == null || domain == AppDomain.CurrentDomain) { return(new LocalExecutor(r.CompiledAssembly)); } // load assembly into isolated app domain (without leaking into this one) RemoteExecutor remote = (RemoteExecutor) domain.CreateInstanceAndUnwrap(typeof(RemoteExecutor).Assembly.FullName, typeof(RemoteExecutor).FullName); remote.LoadFrom(r.PathToAssembly); return(remote); }