2017-05-14 5 views
2

Wie konvertiere ich diese Lambda Expression Baum in C#Erstellen von dynamischen Ausdrucksbaum

var FieldName="SomeDynamicField"; 
var param = "SomeParam" 
//Lambda to beCreated 
x=>x.FieldName!=null && x.FieldName.ToLower().Contains(param) 

habe ich versucht, diese so weit

private static Expression GetPropertyExpression(PropertyInfo prop, ParameterExpression paramExpr, ConstantExpression valueExpr) { 
    var memberAcc = Expression.MakeMemberAccess(paramExpr, prop); 
    Console.WriteLine(memberAcc); 
    var containsMember = typeof(string).GetMethod("Contains"); 
    var toLower= typeof(String).GetMethod("ToLower",new [] {typeof(string)}); 
    var ttt=Expression.Call(memberAcc,containsMember, valueExpr); 
    return Expression.Call(memberAcc,containsMember, valueExpr); 
} 
+1

Was haben Sie bisher versuchen? Wo steckst du fest? – Icepickle

+0

Ich habe versucht, diesen Code zu schreiben jede List.it filtern arbeitet aber auf Groß –

+0

private static Expression GetPropertyExpression (Property stütze, Parameterexpression paramExpr, ConstantExpression valueExpr) \t { \t \t var memberAcc = Expression.MakeMemberAccess (paramExpr, Prop); \t \t // Console.WriteLine (memberAcc); \t \t var containsMember = typeof (string) .GetMethod ("Enthält"); \t \t var toLower = typeof (String) .GetMethod ("ToLower", neu [] {typeof (string)}); \t \t var ttt = Expression.Call (memberAcc, containsMember, valueExpr); \t \t Rückgabe Expression.Call (memberAcc, enthältMember, WertExpr); \t} –

Antwort

1

Sie können es selbst machen etwas einfacher. Anstatt die Methode Contains zu verwenden, die interessanterweise die StringComparison nicht unterstützt, die als Parameter übergeben werden soll, können Sie die Methode IndexOf verwenden.

Sie können es wie so implementieren:

public static Expression<Func<T, bool>> ContainsValue<T>(string fieldName, string val) { 
    var type = typeof(T); 
    var member = Expression.Parameter(type, "param"); 
    var memberExpression = Expression.PropertyOrField(member, fieldName); 
    var targetMethod = memberExpression.Type.GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); 
    var methodCallExpression = Expression.Call(memberExpression, targetMethod, Expression.Constant(val), Expression.Constant(StringComparison.CurrentCultureIgnoreCase)); 

    return Expression.Lambda<Func<T, bool>>( 
     Expression.AndAlso(
      Expression.NotEqual(memberExpression, Expression.Constant(null)), 
      Expression.GreaterThanOrEqual(methodCallExpression, Expression.Constant(0)) 
     ), 
     member 
    ); 
} 

Der Trick dabei ist, dass ich die IndexOf Methode mit einem GreaterThanOrEqual Anruf mit einem Wert von 0

Das am Ende gibt für einen Test kombinieren Klasse folgender Ausdruck

((param.Parameter != null) AndAlso (param.Parameter.IndexOf("test", CurrentCultureIgnoreCase) >= 0)) 

Ein Beispiel, können Sie hier auf den dotnetfiddle finden, aber ich fügte auch den vollständigen Code bel ow

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 

public class Program 
{ 
    public static Expression<Func<T, bool>> ContainsValue<T>(string fieldName, string val) { 
     var type = typeof(T); 
     var member = Expression.Parameter(type, "param"); 
     var memberExpression = Expression.PropertyOrField(member, fieldName); 
     var targetMethod = memberExpression.Type.GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); 
     var methodCallExpression = Expression.Call(memberExpression, targetMethod, Expression.Constant(val), Expression.Constant(StringComparison.CurrentCultureIgnoreCase)); 

     return Expression.Lambda<Func<T, bool>>( 
      Expression.AndAlso(
       Expression.NotEqual(memberExpression, Expression.Constant(null)), 
       Expression.GreaterThanOrEqual(methodCallExpression, Expression.Constant(0)) 
      ), 
      member 
     ); 
    } 

    public static void Main() 
    { 
     var items = new List<Test>() { 
      new Test() { Parameter = "Alpha" }, 
      new Test(), 
      new Test() { Parameter = "Test" }, 
      new Test() { Parameter = "test" }, 
      new Test() { Parameter = "TEST" }, 
      new Test() { Parameter = "Contains test" } 
     }; 
     var expr = ContainsValue<Test>("Parameter", "test"); 
     // you can see the body here 
     Console.WriteLine(expr.Body); 
     // and the result 
     var results = items.Where(expr.Compile()).Select(t => t.Parameter).ToList(); 
     Console.WriteLine("Results: {0}", string.Join(",", results)); 
     Console.WriteLine("Total results: {0}", results.Count); 
    } 

    public class Test { 
     public string Parameter { get;set; } 
    } 
} 

Ausgänge:

((param.Parameter != null) AndAlso (param.Parameter.IndexOf("test", CurrentCultureIgnoreCase) >= 0)) 
Results: Test,test,TEST,Contains test 
Total results: 4 
+0

Danke Icepickle, ich möchte, dass es für Klassen mit gängigen Datentypen wie Strings, Dezimalzahlen, Doppel und so weiter funktioniert. Derzeit funktioniert es so gut, aber nur auf String-Feldern –

+0

@EmmanuelOgoma Das ist natürlich möglich, dafür gibt es viele verschiedene Ausdrücke. Sie haben jedoch keine Contains-Methode, es gibt beispielsweise viel mehr zu tun. Je nachdem, wie man später Ausdrücke kombinieren möchte, kann es ziemlich viel Arbeit sein;) – Icepickle

+0

dieses Lambda funktioniert, aber ich weiß nicht, wie ich seinen Ausdruck erstellen soll. Beachten Sie die Tostring-Methode namens x => x.FieldName! = null && x.FieldName.Tostring(). ToLower(). Enthält (param) –