2011-10-13 5 views
2

Так что я пытаюсь использовать деревья выражений для применения предиката к каждому значению в коллекции (прочитайте карту или список.All (предикат)). Похоже, что я не получаю входной параметр в предикат, привязанный к значению, предоставленному All, и я немного застреваю. Вот код (с помощью LINQPad), что я работаю с ::C# Связывание дерева выражений

public class SomeType 
{ 
    public IEnumerable<bool> Collection { get; set; } 
} 

void Main() 
{ 
    var list = new SomeType { 
    Collection = new List<bool> { true, true, true } 
    }; 
    var functor = Compiler((SomeType t) => t.Collection, (bool x) => x); 
    functor(list).Dump(); 
} 

MethodInfo FindMethod<TInput>(Type location, string name) 
{ 
    var handle = location 
     .GetMethods(BindingFlags.Static | BindingFlags.Public) 
     .Where(method => method.Name == name).First(); 

    return handle.MakeGenericMethod(typeof(TInput)); 
} 

Predicate<TObject> Compiler<TObject, TProperty>(
    Expression<Func<TObject, IEnumerable<TProperty>>> selector, 
    Expression<Predicate<TProperty>> predicate) 
{ 
    var query = FindMethod<TProperty>(typeof(Enumerable), "All"); 
    var expression = Expression.Call(query, 
     new Expression[] { 
      Expression.Invoke(selector, selector.Parameters), 
      Expression.Lambda<Func<TProperty, bool>>(predicate.Body, 
         Expression.Parameter(typeof(TProperty))), 
     });   

    return Expression.Lambda<Predicate<TObject>>(expression, 
     selector.Parameters).Compile(); 
} 

Спасибо и извините, если это был дан ответ на другой вопрос (я посмотрел на некоторое время).

ответ

1

Это действительно работает, но мне пришлось изменить Predicate<TObject> на Func<TObject, bool>. Если хочешь, я могу попытаться изменить его.

static Predicate<TObject> Compiler<TObject, TProperty>(
    Expression<Func<TObject, IEnumerable<TProperty>>> selector, 
    Expression<Func<TProperty, bool>> predicate) 
{ 
    var query = FindMethod<TProperty>(typeof(Enumerable), "All"); 
    var expression = Expression.Call(
     query, 
     Expression.Invoke(selector, selector.Parameters), 
     predicate); 

    return Expression 
     .Lambda<Predicate<TObject>>(expression, selector.Parameters) 
     .Compile(); 
} 

5 минут спустя ... И если вы действительно хотите использовать Predicate<TObject> ...

static Predicate<TObject> Compiler<TObject, TProperty>(
    Expression<Func<TObject, IEnumerable<TProperty>>> selector, 
    Expression<Predicate<TProperty>> predicate) 
{ 
    var query = FindMethod<TProperty>(typeof(Enumerable), "All"); 

    var predicateAsFunc = Expression.Lambda<Func<TProperty, bool>>(
     predicate.Body, 
     predicate.Parameters); 

    var expression = Expression.Call(
     query, 
     Expression.Invoke(selector, selector.Parameters), 
     predicateAsFunc); 

    return Expression 
     .Lambda<Predicate<TObject>>(expression, selector.Parameters) 
     .Compile(); 
} 
+0

Я понятия не имею, почему я не просто передать параметры предиката (Вздох). Да, я должен использовать предикат, потому что он уже сильно привязан к остальной части кода. Благодаря! – Bashwork

+0

@Bashwork Если вам нужно, я немного сократил его. Теперь я повторно использую 'select.Parameters' (одна строка меньше) – xanatos

Смежные вопросы