Динамическое где для списка <T> - PullRequest
5 голосов
/ 07 августа 2009

Я пытаюсь создать динамический фильтр для различных классов.Мы только знали бы во время выполнения, с каким типом мы имеем дело.Мне нужно, чтобы ColumnName было фактическим столбцом (а не строковым значением).

Есть ли простой способ преобразовать строку в столбец?

public static List<T> Filter<T>
    (this List<T> Source, string ColumnName, 
    string TypeOfCompare, string CompValue)
{
    IQueryable<T> matches = Source.AsQueryable();

    if (ColumnName.Length > 0)
    {
        matches = (IEnumerable)matches.Where(a => ColumnName == CompValue)
    }

    List<T> ReturnList2 = new List<T>();
    ReturnList2 = matches.ToList();
    return ReturnList2;
}

Ответы [ 3 ]

12 голосов
/ 07 августа 2009

В основном вам нужно построить дерево выражений. К счастью, это не очень сложно, используя Expression.Property. Вы можете либо передать это в Queryable.Where, либо скомпилировать и передать в Enumerable.Where. (Очевидно, вам нужно использовать что-то вроде Expression.Equal также, в зависимости от типа сравнения, которое вы пытаетесь сделать.)

Является ли CompValue фактическим значением? Что должно быть TypeOfCompare? 1013 *

Я не уверен, где LINQ to Entities вписывается в это, либо ... вы действительно используете LINQ to Objects, насколько я могу видеть.

РЕДАКТИРОВАТЬ: Хорошо, вот образец. Предполагается, что вы хотите равенства, но если да, то делает то, что вы хотите. Я не знаю, как влияет на производительность компиляция дерева выражений каждый раз - вы можете кэшировать делегат для любой заданной комбинации имя / значение:

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

static class Extensions
{
    public static List<T> Filter<T>
        (this List<T> source, string columnName, 
         string compValue)
    {
        ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
        Expression property = Expression.Property(parameter, columnName);
        Expression constant = Expression.Constant(compValue);
        Expression equality = Expression.Equal(property, constant);
        Expression<Func<T, bool>> predicate =
            Expression.Lambda<Func<T, bool>>(equality, parameter);

        Func<T, bool> compiled = predicate.Compile();
        return source.Where(compiled).ToList();
    }
}

class Test
{
    static void Main()
    {
        var people = new[] {
            new { FirstName = "John", LastName = "Smith" },
            new { FirstName = "John", LastName = "Noakes" },
            new { FirstName = "Linda", LastName = "Smith" },
            new { FirstName = "Richard", LastName = "Smith" },
            new { FirstName = "Richard", LastName = "Littlejohn" },
        }.ToList();

        foreach (var person in people.Filter("LastName", "Smith"))
        {
            Console.WriteLine(person);
        }
    }
}
0 голосов
/ 07 августа 2009

Вы ищете что-то вроде этого: http://naspinski.net/post/Writing-Dynamic-Linq-Queries-in-Linq-to-Entities.aspx В противном случае вы должны обрабатывать каждый случай отдельно, как показано ниже:

if (columnName == "blah")
  matches = matches.Where(i => i.Blah == Value);
if (columnName == "name")
  matches = matches.Where(i => i.Name == Value);
0 голосов
/ 07 августа 2009

Вместо строки ColumnName нельзя ли передать селектор для этого столбца (я понимаю, что это не всегда возможно, но на всякий случай ...) Тогда вы могли бы это использовать.

Кстати, код слишком сложный. Это должно работать:

public static List<T> Filter<T>(
    this List<T> Source, Func<T, string> selector, string CompValue)
{
    return Source.Where(a => selector(a) == CompValue).ToList();
}

Затем вы можете вызвать код следующим образом:

var result = myList.Filter(x => x.ColumnName, "foo");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...