Вложенные общие лямбды в LINQ - PullRequest
5 голосов
/ 14 октября 2011

Я схожу с ума, пытаясь понять выражения в LINQ.Любая помощь очень ценится (даже говорит мне, что я совершенно не в себе).

Допустим, у меня есть три класса

public class Person
{
    public string Name { get; set;}
    public IEnumerable<PersonLocation> Locations { get; set;}
    public IEnumerable<PersonEducation> Educations { get; set:}
}

public class PersonLocation
{
    public string Name { get; set;}
    public string Floor { get; set;}
    public string Extension { get; set;}
}

public class PersonEducation
{
   public string SchoolName { get; set;}
   public string GraduationYear { get; set;}
}

Я пытаюсь создать метод, который принимаетв строке, такой как Locations.Name или Locations.Floor или Educations.SchoolName, которая затем создаст динамический запрос linq

IEnumerable<Person> people = GetAllPeople();
GetFilteredResults(people, "Location.Name", "San Francisco");
GetFilteredResults(people, "Location.Floor", "17");
GetFilteredResults(people, "Educations.SchoolName", "Northwestern");

Этот метод GetFilteredResults(IEnumerable<Person> people, string ModelProperty, string Value) должен создать выражение, примерно эквивалентное people.Where(p => p.Locations.Any(pl => pl.Name == Value);

У меня это работает, если ModelProperty является строкой, т.е. people.Where (p => p.Name == Value) выглядит так:

string[] modelPropertyParts = ModelProperty.Split('.');
var prop = typeof(Person).GetProperty(modelPropertyParts[0]);
var sourceParam = Expression.Parameter(typeof(Person), "person");
var expression = Expression.Equal(Expression.PropertyOrField(sourceParam, modelPropertyParts[0]), Expression.Constant(option.Name));
var whereSelector = Expression.Lambda<Func<Person, bool>>(orExp, sourceParam);
return people.Where(whereSelector.Compile());

Вот что у меня естья играл с типом IEnumerable, но я просто не могу получить внутренний Any, который кажется правильным, подключенный к внешнему Where:

/*i.e. modelPropertyParts[0] = Locations & modelPropertyParts[1] = Name */
string[] modelPropertyParts = ModelProperty.Split('.');

var interiorProperty = prop.PropertyType.GetGenericArguments()[0];
var interiorParameter = Expression.Parameter(interiorProperty, "personlocation");
var interiorField = Expression.PropertyOrField(interiorParameter, modelPropertyParts[1]);
var interiorExpression = Expression.Equal(interiorField, Expression.Constant(Value));
var innerLambda = Expression.Lambda<Func<PersonLocation, bool>>(interiorExpression, interiorParameter);

var outerParameter = Expression.Parameter(typeof(Person), "person");
var outerField = Expression.PropertyOrField(outerParameter, modelPropertyParts[0]);
var outerExpression = ??
var outerLambda == ??

return people.Where(outerLambda.Compile());

1 Ответ

1 голос
/ 15 октября 2011

Проблема в том, что System.Linq.Enumerable.Any - это метод статического расширения.

Ваш outerExpression должен ссылаться System.Linq.Enumerable.Any(IEnumerable<T>, Func<T, bool>):

var outerExpression = Expression.Call(
    typeof(System.Linq.Enumerable), 
    "Any", 
    new Type[] { outerField.Type, innerLambda.Type }, 
    outerField, innerLambda);

Посмотрите эти ссылки для получения дополнительной информации:

...