2012-01-13 21 views
6

Duplicar posible:
Is there an easy way to parse a (lambda expression) string into an Action delegate?Creación de expresión lambda de una cadena

me gustaría almacenar expresiones lambda como cadenas en un archivo de configuración y en tiempo de ejecución cargar dinámicamente estas cadenas en las expresiones lambda Cª#. Mi objetivo es configurar e inyectar reglas. ¿Hay utilidades disponibles para crear expresiones lambda a partir de una cadena?

¿Existen otras soluciones livianas para el mismo objetivo?

+0

¿Existe un duplicado? [http://stackoverflow.com/questions/714799/is-there-an-easy-way-to-parse-a-lambda-expression-string-into-an-action-delega](http://stackoverflow. com/questions/714799/is-there-an-easy-way-to-parse-a-lambda-expression-string-into-an-action-delega) – MNIK

+0

Posiblemente relacionado: http://stackoverflow.com/questions/ 8327831/could-net-be-parsed-and-evaluate-at-runtime/8328096 # 8328096 – sehe

+0

Votación para cerrar. Nota al margen: considere más lenguajes amigables para scripting para su lógica LUA (http://stackoverflow.com/questions/1283641/lua-wrapper-for-c), IronPython, –

Respuesta

4

Si conoce el tipo de expresiones de antemano, puede compilarlas como parte de una clase y luego sacarlas del ensamblaje resultante.

Aquí hay un ejemplo que lo hace (con las expresiones que toman una cadena y devuelven un bool) y ejecuta las reglas resultantes.

con el contenido de C: \ temp \ rules.txt siendo esta:

file => file.Length == 0 
file => System.IO.Path.GetExtension(file) == ".txt" 
file => file == null 

A continuación, la salida resultante es la siguiente:

Rules found in file: 
file => file.Length == 0, 
file => System.IO.Path.GetExtension(file) == ".txt", 
file => file == null, 

Checking rule file => (file.Length == 0) against input c:\temp\rules.txt: False 
Checking rule file => (GetExtension(file) == ".txt") against input c:\temp\rules.txt: True 
Checking rule file => (file == null) against input c:\temp\rules.txt: False 

Fuente:

using System; 
using System.Xml.Linq; 
using System.Linq; 
using System.IO; 
using Microsoft.CSharp; 
using System.CodeDom.Compiler; 
using System.Reflection; 
using System.Linq.Expressions; 

class Program 
{ 
    private const string classTemplate = @" 
      using System; 
      using System.Linq.Expressions; 

      public static class RulesConfiguration 
      {{ 
       private static Expression<Func<string, bool>>[] rules = new Expression<Func<string, bool>>[] 
       {{ 
        {0} 
       }}; 

       public static Expression<Func<string, bool>>[] Rules {{ get {{ return rules; }} }} 
      }} 
     "; 

    static void Main(string[] args) 
    { 
     var filePath = @"c:\temp\rules.txt"; 
     var fileContents = File.ReadAllLines(filePath); 

     // add commas to the expressions so they can compile as part of the array 
     var joined = String.Join("," + Environment.NewLine, fileContents); 

     Console.WriteLine("Rules found in file: \n{0}", joined); 

     var classSource = String.Format(classTemplate, joined); 

     var assembly = CompileAssembly(classSource); 

     var rules = GetExpressionsFromAssembly(assembly); 

     foreach (var rule in rules) 
     { 
      var compiledToFunc = rule.Compile(); 
      Console.WriteLine("Checking rule {0} against input {1}: {2}", rule, filePath, compiledToFunc(filePath)); 
     } 
    } 

    static Expression<Func<string, bool>>[] GetExpressionsFromAssembly(Assembly assembly) 
    { 
     var type = assembly.GetTypes().Single(); 
     var property = type.GetProperties().Single(); 
     var propertyValue = property.GetValue(null, null); 
     return propertyValue as Expression<Func<string, bool>>[]; 
    } 

    static Assembly CompileAssembly(string source) 
    { 
     var compilerParameters = new CompilerParameters() 
     { 
      GenerateExecutable = false, 
      GenerateInMemory = true, 
      ReferencedAssemblies = 
      { 
       "System.Core.dll" // needed for linq + expressions to compile 
      }, 
     }; 
     var compileProvider = new CSharpCodeProvider(); 
     var results = compileProvider.CompileAssemblyFromSource(compilerParameters, source); 
     if (results.Errors.HasErrors) 
     { 
      Console.Error.WriteLine("{0} errors during compilation of rules", results.Errors.Count); 
      foreach (CompilerError error in results.Errors) 
      { 
       Console.Error.WriteLine(error.ErrorText); 
      } 
      throw new InvalidOperationException("Broken rules configuration, please fix"); 
     } 
     var assembly = results.CompiledAssembly; 
     return assembly; 
    } 
} 
2

Tienes un vistazo a Dynamic Linq. Es una publicación anterior pero siempre útil.

+1

Buena llamada: puede instalar el paquete nuget DynamicQuery (el nombre es "Dynamic Expression API") - ver http://nuget.org/packages/DynamicQuery –

Cuestiones relacionadas