public ExpressionService(ExpressionFeatures features = ExpressionFeatures.None, TraceSource trace = null) { _features = features; _trace = trace; _trace?.TraceInformation($"ExpressionService instantiated with these features: {features}"); _trace?.Flush(); }
private static void EmitMethodSignatures(ExpressionFeatures features, StringBuilder sb, string expressionLine, string[] parameterNames, TraceSource trace) { Func <string, string> parameterLine = type => EmitExpressionParameters(type, parameterNames); if (parameterNames.Length == 0) { // Nothing: sb.AppendLine($" public static object Evaluate()"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); } else { if (features.HasFlag(ExpressionFeatures.UseDynamicBinding)) { // Dynamic: sb.AppendLine($" public static object Evaluate({parameterLine("dynamic")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); } else { // Permutations: EmitTypePermutation(sb, expressionLine, parameterNames, TypePermutations1); } } }
public override object Invoke(ExpressionFeatures features, Type[] types, object[] values) { MethodInfo eval = GetEvaluationMethod(features, types); object result = eval.Invoke(null, values); return(result); }
public void Compare_constants_versus_native(ExpressionFeatures features, int trials) { ExpressionService service = new ExpressionService(features); // Constants: CompareTests("Constants", features.ToString(), () => service.Evaluate("100", null, null, null), "Native", () => ConstantNative(), trials, service, 100); }
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); }
private MethodInfo GetEvaluationMethod(ExpressionFeatures features, Type[] types) { // L2 Cache: MethodInfo if (features.HasFlag(ExpressionFeatures.L2Cache)) { string key = $"{Identifier}_{types.Select(t => t.Name)}"; MethodInfo eval; if (MethodCache.Value.TryGetMethod(key, out eval)) { return(eval); } return(MethodCache.Value.Add(key, GetMethod(types))); } return(GetMethod(types)); }
public QxOptions WithAllowedFeatures(ExpressionFeatures allowedFeatures) => new QxOptions(AllowedFeatures | allowedFeatures, AllowedMembers);
public QxOptions(ExpressionFeatures allowedFeatures, IEnumerable <MemberInfo> allowedMembers) { AllowedFeatures = allowedFeatures; AllowedMembers = allowedMembers; }
public abstract object Invoke(ExpressionFeatures features, Type[] types, object[] values);
private static void EmitMethodSignatures(ExpressionFeatures features, StringBuilder sb, string expressionLine, string[] parameterNames) { Func <string, string> parameterLine = type => EmitExpressionParameters(type, parameterNames); if (parameterNames.Length == 0) { // Nothing: sb.AppendLine($" public static object Evaluate()"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); return; } if (features.HasFlag(ExpressionFeatures.UseDynamic)) { // Dynamic: sb.AppendLine($" public static dynamic Evaluate({parameterLine("dynamic")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); return; } // Byte: sb.AppendLine($" public static object Evaluate({parameterLine("byte")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Int16: sb.AppendLine($" public static object Evaluate({parameterLine("short")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Int32: sb.AppendLine($" public static object Evaluate({parameterLine("int")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Int64: sb.AppendLine($" public static object Evaluate({parameterLine("long")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Single: sb.AppendLine($" public static object Evaluate({parameterLine("float")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Double: sb.AppendLine($" public static object Evaluate({parameterLine("double")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); // Decimal: sb.AppendLine($" public static object Evaluate({parameterLine("decimal")})"); sb.AppendLine($" {{"); sb.AppendLine($" return {expressionLine};"); sb.AppendLine($" }}"); }
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); }
public ExpressionService(ExpressionFeatures features = ExpressionFeatures.Default) { _features = features; }
public AllowedFeaturesScanner(ExpressionFeatures features) { _features = features; }
public static Verifier Create(ExpressionFeatures features) => Verification.CreatePatternedVerifier(new AllowedFeaturesScanner(features).Scan);