2 Stimmen

Ausdruck der Methode im Ausdrucksbaum erhalten

Ich möchte die folgende Abfrage in Ausdrucksbäumen erstellen:

var test = from datarow in tempResults
           where datarow.Field<String>("ColumnName") == "Column"
           select datarow;

Wie kann ich den Ausdruck erstellen:

datarow.Field<String>("ColumnName")?

Ich habe alles ausprobiert und bin sogar beim Abrufen der MethodInfo von Field für die Methode Expression.Call hängen geblieben. Field ist eine Erweiterung Methode von DataRowExtentions.

Muss ich dafür Expression.Call() verwenden? Wie erhalte ich die MethodInfo? Gibt es einen einfacheren Weg, dies zu tun?

Ich habe es versucht:

ParameterAusdruck dataRow = Expression.Parameter(typeof(DataRowExtensions), "dataRow"); Expression left = Expression.Call(dataRow, typeof(DataRowExtensions).GetMethod("Field"));

aber es funktioniert nicht.


Ich möchte dynamische Filter für die Daten in IQueryable tempResults erstellen.

Der Benutzer wird auf der grafischen Benutzeroberfläche Kontrollkästchen ankreuzen, die "Where"-Ausdrücke zu den Daten in tempResults hinzufügen. Wenn der Benutzer "Spalte" auswählt, möchte ich die Datenzeilen anzeigen, bei denen Spaltenname = "Spalte".

Das ist, warum ich die Where-Ausdruck erstellen müssen. aber ich bin so auf die MethodInfo Sache stecken. Ich habe dies auch versucht:

MethodInfo FieldStringMethodInfo = typeof(DataRowExtensions).GetMethod("Field", BindingFlags.Public | BindingFlags.Static);

aber es funktioniert auch nicht.

Gibt es andere Möglichkeiten, dies zu tun?

2voto

Marc Gravell Punkte 970173

Ersetzte Antwort nach Klärung in den Kommentaren:

Für den sukzessiven Aufbau weiterer Filter benötigen Sie keine Ausdrucksbäume; Sie können die .Where mehrmals (je nach Bedarf, einmal pro Suchbegriff) - zum Beispiel:

IEnumerable<DataRow> query = tempResults.AsEnumerable();
if(!string.IsNullOrEmpty(value1)) {
    query = query.Where(row => row.Field<string>("Col1") == value1);
}
if (!string.IsNullOrEmpty(value2)) {
    query = query.Where(row => row.Field<string>("Col2") == value2);
}

Das Einzige, worauf Sie achten müssen, ist die Frage des "Capture"; stellen Sie sicher, dass Sie keine der Dateien wiederverwenden. value1 , value2 usw. - andernfalls gilt der letzte Wert für früher Filter...


Für ein Beispiel einer Delegatenkombination (aus Kommentaren) - beachten Sie, dass ich die DataTable Aspekt hier nur, um das Beispiel kürzer zu machen (es funktioniert identisch):

public static class Predicate {
    public static Func<T, bool> OrElse<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) || rhs(obj);
    }
    public static Func<T, bool> AndAlso<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) && rhs(obj);
    }
}
class Data {
    public string Color { get; set; }
}
class Program {
    static void Main() {
        bool redChecked = true, greenChecked = true; // from UI...
        List<Data> list = new List<Data>() {
            new Data { Color = "red"},
            new Data { Color = "blue"},
            new Data { Color = "green"},
        };
        Func<Data, bool> filter = null;
        if (redChecked) {
            filter = filter.OrElse(row => row.Color == "red");
        }
        if (greenChecked) {
            filter = filter.OrElse(row => row.Color == "green");
        }
        if (filter == null) filter = x => true; // wildcard

        var qry = list.Where(filter);

        foreach (var row in qry) {
            Console.WriteLine(row.Color);
        }
    }
}

(Originalantwort)

Eigentlich wird diese Variante von LINQ keinen Ausdrucksbaum verwenden... es wird einen Delegaten verwenden; aber Sie können den Baum erstellen und kompilieren, wenn Sie wirklich wollen... Ich bin mir allerdings nicht sicher, warum Sie das tun sollten. Was wollen Sie tun? Ich werde ein Beispiel erstellen...


Hier ist es; dies verwendet einen Ausdrucksbaum, aber mir fällt kein einziger guter Grund ein, dies zu tun, außer um zu beweisen, dass man es kann!

public static class MyExtensions
{
    public static IQueryable<TRow> Where<TRow, TValue>(
        this IQueryable<TRow> rows,
        string columnName, TValue value)
        where TRow : DataRow
    {
        var param = Expression.Parameter(typeof(TRow), "row");
        var fieldMethod = (from method in typeof(DataRowExtensions).GetMethods()
                           where method.Name == "Field"
                           && method.IsGenericMethod
                           let args = method.GetParameters()
                           where args.Length == 2
                           && args[1].ParameterType == typeof(string)
                           select method)
                           .Single()
                           .MakeGenericMethod(typeof(TValue));
        var body = Expression.Equal(
            Expression.Call(null,fieldMethod,
                param,
                Expression.Constant(columnName, typeof(string))),
            Expression.Constant(value, typeof(TValue))
        );
        var lambda = Expression.Lambda<Func<TRow, bool>>(body, param);
        return rows.Where(lambda);

    }
}
class Program
{
    static void Main(string[] args)
    {
        DataTable tempResults = new DataTable();
        tempResults.Columns.Add("ColumnName");
        tempResults.Rows.Add("foo");
        tempResults.Rows.Add("Column");

        var test = tempResults.AsEnumerable().AsQueryable()
                   .Where("ColumnName", "Column");
        Console.WriteLine(test.Count());

    }
}

0 Stimmen

Ich möchte dynamische Filter für die Daten in IQueryable<DataRow> tempResults erstellen. Wenn der Benutzer "Column" auswählt, möchte ich die DataRows anzeigen, bei denen ColumnName = "Column" ist. Deshalb muss ich den Where-Ausdruck erstellen. Aber ich hänge so sehr an der MethodInfo thing...., dass ich auch dies versucht habe: MethodInfo FieldStringMethodInfo = typeof(DataRowExtensions).GetMethod("Field<string>", BindingFlags.Public | BindingFlags.Static); es funktioniert auch nicht. Gibt es andere Möglichkeiten, dies zu tun?

0 Stimmen

Danke Marc, das Asenumerable()-Beispiel ist gut, aber ich brauche eine Möglichkeit, es dynamisch zu erstellen, denn der Benutzer kann wählen: Zeile => Zeile.Feld<string>("Spalte1") == Wert1 || Zeile.Feld<string>("Spalte1") == Wert2 und beim nächsten Mal: Zeile => Zeile.Feld<string>("Spalte1") == Wert1 || Zeile. Field<string>("Col1") == value2 || row.Field<string>("Col1") == value3. Deshalb muss ich die Abfrage dynamisch zusammenstellen, d.h. ich muss einen Weg finden, "beliebige Filter zu einer Where-Klausel hinzuzufügen" und erst dann die Abfrage auszuführen. Kann ich das auf einfachere Weise als mit dem Beispiel des Ausdrucksbaums tun?

0 Stimmen

Können Sie ein Beispiel dafür geben, was Sie meinen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X