Лямбда в списке <T>и использование Reflection для получения имен свойств - PullRequest
2 голосов
/ 25 января 2010

Допустим, у вас есть общий класс, который имеет List<T> Items;

Теперь подумайте об этом простом лямбда-выражении:

var result = Items.FindAll(x => x.Name = "Filip");

Это будет работать только до тех пор, пока мы знаем свойства T, чего вы не знаете, когда это универсальный тип.

Поэтому я хотел бы получить свойства, используя Reflection так:

PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public);

и каким-то образом объединить это с вышеприведенным лямбда-выражением, чтобы оно осуществляло поиск во всех открытых свойствах Типа и проверяло, содержит ли оно «Филип», в настоящее время мне все равно, является ли свойство-имя именем или нет.

Возможно ли это?

Ответы [ 2 ]

11 голосов
/ 25 января 2010
var result = Items.FindAll(x => 
    properties.Any(p => p.PropertyType == typeof(string) && 
                        p.GetValue(x, null) == "Filip"));

Очевидно, что это упрощенное, оптимистичное сравнение строк (вы можете использовать, например, string.Compare), но это должно прояснить идею.

Редактировать

dtb дает хорошее предложение по использованию деревьев выражений. Вы могли бы выполнить то, что вам нужно, более быстрым способом, как это:

public static class PropertyScanner
{
    static Func<TType, bool> CreatePredicate<TType, TValue>(TValue value, IEqualityComparer<TValue> comparer)
    {
        var arg = Expression.Parameter(typeof(TType), "arg");

        Expression body = null;

        Expression<Func<TValue, TValue, bool>> compare = (val1, val2) => comparer.Equals(val1, val2);

        foreach (PropertyInfo property in typeof(TType).GetProperties(BindingFlags.Public))
        {
            if (property.PropertyType == typeof(TValue) || typeof(TValue).IsAssignableFrom(property.PropertyType))
            {
                Expression prop = Expression.Equal(Expression.Invoke(compare, new Expression[]
                                       {
                                           Expression.Constant(value),
                                           Expression.Property(arg, property.Name)
                                       }),
                                               Expression.Constant(0));

                if (body == null)
                {
                    body = prop;
                }
                else
                {
                    body = Expression.OrElse(body, prop);
                }
            }
        }

        return Expression.Lambda<Func<TType, bool>>(body, arg).Compile();
    }

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value)
    {
        return ScanProperties<TType, TValue>(source, value, EqualityComparer<TValue>.Default);
    }

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value, IEqualityComparer<TValue> comparer)
    {
        return source.Where(CreatePredicate<TType, TValue>(value, comparer));
    }
}

Это позволит вам сделать что-то вроде этого:

var result = Items.ScanProperties("Filip").ToList();
3 голосов
/ 25 января 2010

Вы можете использовать деревья выражений для создания лямбды на лету:

Func<T, bool> CreatePredicate<T>()
{
    var arg = Expression.Parameter(typeof(T), "arg");
    var body = Expression.Equal(Expression.Property(arg, "Name"),
                                Expression.Constant("Filip"));
    return Expression.Lambda<Func<T, bool>>(body, arg).Compile();
}

IEnumerable<T> GetTWhereNameIsFilip<T>(IEnumerable<T> source)
{
    Func<T, bool> predicate = CreatePredicate<T>();
    // cache predicate for max performance

    return source.Where(predicate);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...