2009-05-25 9 views
-2

Ich habe ein bisschen eine Herausforderung, wo ich einen Ausdrucksbaum erstellen muss, um eine Abfrage durch den Benutzer eingegeben darzustellen. Da ich nicht die Zeit habe, alle möglichen Fälle von Benutzereingaben zu erstellen, dachte ich, dass Ausdrucksbäume mir helfen würden, dies zu lösen.Ausdruck gegen Prädikat Probleme

Zum größten Teil hat es. Ich bin jedoch ein wenig ratlos. Ich bin in dem folgenden Code, der versucht, eine List.Find mit einem dynamisch erstellten Ausdruck auszuführen. Der Ausdruck, kurz gesagt, ist dies:

list.Find(m => m.ListOfStrings.Exists(s => s == "cookie")); 

wo m

class MyClass 
{ 
    public List<string> ListOfStrings { get; set; } 
} 

ist die ich bisher bekommen habe als

s => s == "cookie" 

mit Ausdrücken zu erstellen, kein Problem. Ich habe auch erklärt, eine Method für Exists

var existsMethod = typeof(MyClass) 
     .GetProperty("ListOfStrings") 
     .PropertyType 
     .GetMethod("Exists"); 

Das einzige Problem, das ich habe, einen Ausdruck zu schaffen wie so

var findLambda = Expression.Lambda(
    Expression.Call(
     Expression.Property(
      Expression.Parameter(typeof(MyClass), "m"), 
      typeof(MyClass).GetProperty("ListOfStrings")), 
     existsMethod, 
     existsLambda), 
    Expression.Parameter(
     typeof (MyClass), 
     "m")); 

mit dem Lambda als Parameter die Methode aufzurufen Es gibt eine verständliche Ausnahme, dass

Expression of type 'System.Func`2[System.String,System.Boolean]' cannot be used for parameter of type 'System.Predicate`1[System.String]' of method 'Boolean Exists(System.Predicate`1[System.String])' 

Wie zum Teufel kann ich das überwinden?

Voll Code:

private class MyClass 
{ 
    public List<string> ListOfStrings { get; set; } 
} 

public void SomeMethod() 
{ 
    var myObject = new MyClass(); 
    myObject.ListOfStrings = new List<string>(); 
    myObject.ListOfStrings.Add("cookie"); 
    myObject.ListOfStrings.Add("biscuit"); 

    List<MyClass> list = new List<MyClass>(); 
    list.Add(myObject); 

    var existsLambda = Expression.Lambda(
     Expression.Equal(
      Expression.Parameter(typeof(string), "s"), 
      Expression.Constant("cookie")), 
     Expression.Parameter(typeof(string), "s")); 

    var existsMethod = typeof(MyClass).GetProperty("ListOfStrings").PropertyType.GetMethod("Exists"); 

    var findLambda = Expression.Lambda(
     Expression.Call(
      Expression.Property(
       Expression.Parameter(typeof(MyClass), "m"), 
       typeof(MyClass).GetProperty("ListOfStrings")), 
      existsMethod, 
      existsLambda), 
     Expression.Parameter(
      typeof (MyClass), 
      "m")); 

    list.Find((Predicate<MyClass>)findLambda.Compile()); 
} 
+0

Ich weiß, dass ‚dynamische‘ Benutzereingabe ein bisschen eine Herausforderung in Linq, aber wenn der Benutzer Gibt nur unterschiedliche Werte für ein zu filterndes Feld oder verschiedene Filter für dasselbe Element an. Sie können einfach Where-Klauseln an den ursprünglichen Filter anhängen und die Eingabe im Filter selbst verwenden. Kurz gesagt: Es ist völlig unklar, warum Sie all diese Probleme durchmachen und warum Sie Where-Klauseln nicht anhängen können, wenn es nötig ist. –

+0

@Frans, weil ich den Benutzer nicht einfach verschiedene Werte für ein statisch definiertes Feld angeben lassen kann. Ich brauche eine vollständig dynamische Lösung, um a) die Menge an Code zu reduzieren, die gepflegt werden muss, und c) unter all dem eine Erweiterbarkeit mit neuen Klassen in der Klassenbibliothek anzubieten. –

Antwort

2

Die Delegierten haben verschiedene Typen:

public delegate bool Predicate<T>(T obj); 
public delegate TResult Func<T, TResult>(T arg); 

Die Exists Methode (und die Find) Predicate<T> erwarten. Der Lambda-Ausdruck kompiliert zur Laufzeit zu Func<T, TResult>.

Versuchen Sie Folgendes:

var existsLambda = Expression.Lambda(typeof(Predicate<string>), 
       Expression.Equal(
        Expression.Parameter(typeof(string), "s"), 
        Expression.Constant("cookie")), 
       Expression.Parameter(typeof(string), "s")); 

Sie können auch die Verwendung generische Lambda Function:

var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
        Expression.Parameter(typeof(string), "s"), 
        Expression.Constant("cookie")), 
       Expression.Parameter(typeof(string), "s")); 
+0

Ja, ich wusste, dass es verschiedene Typen waren, ich dachte nur, es wäre schlau genug, einen Func in ein Prädikat zu verwandeln, da ein Prädikat bool zurückgibt ... Ich werde es versuchen, wenn Ich gehe zurück zur Arbeit - danke! –

+0

Ich weiß auch, was es zur Laufzeit kompiliert, das Problem war, dass ich ein Prädikat nicht als Parameter senden konnte, da Expression.Call einen Ausdruck erwartet - Ihr Code scheint dieses Problem zu lösen. Wie ich schon sagte, ich werde es morgen bei der Arbeit versuchen. Danke noch einmal. =) –

+0

Ehrfürchtig. So eine einfache Änderung. Vielen Dank. =) –

0

Wenn man sich die Nachricht aus, es Sie, dass Prädikats erzählt, ist nicht kompatibel mit Func.

Nun wird Prädikats als solche definiert:

public delegate bool Predicate<T>(
    T obj 
) 

und Sie haben Func als solche:

public delegate TResult Func<T, Result>(
    T arg1 
) 

zusammen, Sie versuchen, diese 2 Delegierten kompatibel zu machen:

public delegate bool MyClassPredicate (MyClass obj) 
public delegate bool StringFunc (string arg1) 

Ie. Zeichenfolge! = MyClass.

Ich hoffe, es hat Sinn gemacht.

+0

Das hat mit meinem Fehler überhaupt nichts zu tun. =) –

+0

Du hast recht, ich habe es total geschafft, das alles falsch zu lesen, das heißt, versuche Brunos Vorschlag. – kastermester

Verwandte Themen